Making Single Page Apps Accessible #LaraconAU @jessbudd4 - - PowerPoint PPT Presentation

making single page apps accessible
SMART_READER_LITE
LIVE PREVIEW

Making Single Page Apps Accessible #LaraconAU @jessbudd4 - - PowerPoint PPT Presentation

Making Single Page Apps Accessible #LaraconAU @jessbudd4 @jessbudd4 = @jessbudd4 @jessbudd4 @jessbudd4 Jess Budd Front-end Developer & Accessibility Consultant @jessbudd4 Are JavaScript


slide-1
SLIDE 1 @jessbudd4 #LaraconAU

Making Single Page Apps Accessible

slide-2
SLIDE 2 @jessbudd4

🚷 📲

😮 🤖

slide-3
SLIDE 3 @jessbudd4

 = 💶

slide-4
SLIDE 4 @jessbudd4
slide-5
SLIDE 5 @jessbudd4

😭

slide-6
SLIDE 6

Jess Budd

@jessbudd4 Front-end Developer & Accessibility Consultant
slide-7
SLIDE 7 @jessbudd4

Are JavaScript frameworks bad for accessibility?

slide-8
SLIDE 8 @jessbudd4

Nothing in React prevents us from building accessible web apps

  • Leslie Cohn-Wein, Netlify
slide-9
SLIDE 9 @jessbudd4

What is web accessibility?

slide-10
SLIDE 10 @jessbudd4

Removing barriers that prevent people with disabilities using your website

slide-11
SLIDE 11 @jessbudd4

1 in 5

Australians experience some form of disability Source: www.and.org.au/pages/disability-statistics.html
slide-12
SLIDE 12 @jessbudd4

357,000

Australians have a visual impairment Source: www.and.org.au/pages/disability-statistics.html
slide-13
SLIDE 13 @jessbudd4

1 in 6

Australians are affected by hearing loss Source: www.and.org.au/pages/disability-statistics.html
slide-14
SLIDE 14 @jessbudd4

Accessibility benefits everyone

slide-15
SLIDE 15 @jessbudd4
slide-16
SLIDE 16

Who is most impacted?

slide-17
SLIDE 17

Keyboard users

slide-18
SLIDE 18

Screenreade r users

slide-19
SLIDE 19 @jessbudd4

Semantic HTML

slide-20
SLIDE 20 @jessbudd4

screenshot

  • f link list
  • n
slide-21
SLIDE 21 // not very accessible card component <div class="product"> <div class=“name"> Product name </div> <div class="description"> Description of product </div> <div class="button">Add to cart</div> </div>
slide-22
SLIDE 22
slide-23
SLIDE 23 // more accessible card component <li> <h2> Product name </h2> <p> Description of product </p> <button>Add to cart</button> </li>
slide-24
SLIDE 24 // more accessible card component <li> <h2> Product name </h2> <p> Description of product </p> <button>Add to cart</button> </li>
slide-25
SLIDE 25 @jessbudd4

Divs are not buttons

slide-26
SLIDE 26 <div tabindex="0" role="button"
  • nKeyUp={keyUpHandler}
  • nClick={clickHandler}
class="button"> Add to cart </div>
slide-27
SLIDE 27 <div tabindex="0" role="button"
  • nKeyUp={keyUpHandler}
  • nClick={clickHandler}
class="button"> Add to cart </div>
slide-28
SLIDE 28 <div tabindex="0" role="button"
  • nKeyUp={keyUpHandler}
  • nClick={clickHandler}
class="button"> Add to cart </div>
slide-29
SLIDE 29 <div tabindex="0" role="button"
  • nKeyUp={keyUpHandler}
  • nClick={clickHandler}
class="button"> Add to cart </div> <button
  • nClick={clickHandler}>
Add to cart </button>

👎

slide-30
SLIDE 30 @jessbudd4

Give buttons some ❤

slide-31
SLIDE 31 @jessbudd4

Fragments for valid html

slide-32
SLIDE 32 // not allowed render() { return ( <li>Hello</li> <li>World</li> ); }
slide-33
SLIDE 33 // not allowed render() { return ( <li>Hello</li> <li>World</li> ); } // solution??? render() { return ( <div> <li>Hello</li> <li>World</li> </div> ); }

👏

slide-34
SLIDE 34 // fragments syntax render() { return ( <React.fragment> <li>Hello</li> <li>World</li> </React.fragment> ); }
slide-35
SLIDE 35 @jessbudd4

Vue Fragments

www.medium.com/the-vue-point/plans-for-the-next-iteration-of-vue-js-777ffea6fabf Vue-fragment
slide-36
SLIDE 36 @jessbudd4

Inputs & labels

slide-37
SLIDE 37 // label not linked to input <label> Dog breed: </label> <input type="text" name="breed" />
slide-38
SLIDE 38 // explicitly linked label to input <label for="uniqueId"> Dog breed: </label> <input id="uniqueId" type="text" name=”breed” />
slide-39
SLIDE 39 // “for” becomes “htmlFor” in JSX <label htmlFor="uniqueId"> Dog breed: </label> <input id="uniqueId" type="text" name="breed" />
slide-40
SLIDE 40 @jessbudd4

What if I can't set a unique ID in advance?

slide-41
SLIDE 41 // implicitly linked label to input <label> Dog breed: <input type="text" name="breed"/> </label>
slide-42
SLIDE 42 @jessbudd4

What if the design doesn’t have labels?

slide-43
SLIDE 43 // label hidden with css is still announced <label class=“sr-only“ for=“dogBreed”> Dog breed: </label> <input id=“dogBreed” type="text" name=”breed" />
slide-44
SLIDE 44 @jessbudd4

Hit Area

slide-45
SLIDE 45 @jessbudd4

Page titles

slide-46
SLIDE 46

Click to edit

slide-47
SLIDE 47 // page title appears in browser tab <head> <meta charset="utf-8"> <title>Dogs Are The Best</title> <link rel="stylesheet" href="style.css"> </head>
slide-48
SLIDE 48 // code executes when component mounts // same as the mounted hook in Vue componentDidMount() { document.title = ‘Heckin’ Good Doggo’; }
slide-49
SLIDE 49 // update page title on routing componentDidMount() { document.title = ‘Heckin’ Good Doggo’; }
slide-50
SLIDE 50

Click to edit

slide-51
SLIDE 51 @jessbudd4

Visible focus styles

slide-52
SLIDE 52 @jessbudd4 Safari: Firefox: Chrome:

Default browser styles

slide-53
SLIDE 53 @jessbudd4

Meme where am I /lost

slide-54
SLIDE 54 @jessbudd4

Screen shot of page with masses of links and question marks

???

slide-55
SLIDE 55 /* don't just remove */ *:focus {
  • utline: none;
}

slide-56
SLIDE 56 /* don't just remove */ *:focus {
  • utline: none;
}

✅ ❌

/* replace with something! */ *:focus { /* branded focus styles here */ border: 2px dotted currentColor; }
slide-57
SLIDE 57 /* extend hover styles */ .button:hover, .button:focus { border: 5px solid #33ffdb; }
slide-58
SLIDE 58 @jessbudd4

Focus management

slide-59
SLIDE 59 @jessbudd4

Single page applications use silent routing

slide-60
SLIDE 60 @jessbudd4

Video of default browser behaviour

slide-61
SLIDE 61 @jessbudd4

Move focus to new content

slide-62
SLIDE 62

Tabindex Explained

tabindex=”0" // makes element focusable in tab/DOM order tabindex=”-1" // makes elements focusable by scripting only tabindex=”5” // Danger Will Robinson! // tabindex becomes tabIndex (camelCase) in JSX
slide-63
SLIDE 63 @jessbudd4

Use React Refs

slide-64
SLIDE 64 class PageHeading extends React.Component { constructer(props) { super(props); this.content = React.createRef(); // Create Ref } componentDidMount() { this.content.focus(); // Move focus to ref } render() { return ( <h1 tabindex="-1" ref={this.content}> // Reference Doggos, Puppers and Floofers </h1> ); } }
slide-65
SLIDE 65 class PageHeading extends React.Component { constructer(props) { super(props); this.content = React.createRef(); // Create Ref } componentDidMount() { this.content.focus(); // Move focus to ref } render() { return ( <h1 tabindex="-1" ref={this.content}> // Reference Doggos, Puppers and Floofers </h1> ); } }
slide-66
SLIDE 66 class PageHeading extends React.Component { constructer(props) { super(props); this.content = React.createRef(); // Create Ref } componentDidMount() { this.content.focus(); // Move focus to ref } render() { return ( <h1 tabindex="-1" ref={this.content}> // Reference Doggos, Puppers and Floofers </h1> ); } }
slide-67
SLIDE 67 // update page title // and move users focus componentDidMount() { document.title = ‘Doggos be happy’; this.content.focus(); }
slide-68
SLIDE 68 @jessbudd4

Tooling & Testing

slide-69
SLIDE 69 @jessbudd4

eslint-plugin-jsx-a11y

eslint-plugin-jsx-a11y eslint-plugin-vue-a11y
slide-70
SLIDE 70 @jessbudd4

Axe-core

react-axe vue-axe
slide-71
SLIDE 71 @jessbudd4

Google Lighthouse

https://developers.google.com/web/tools/lighthouse
slide-72
SLIDE 72 @jessbudd4

Accessibility Insights

https://accessibilityinsights.io/
slide-73
SLIDE 73 https://www.matuzo.at/blog/building-the-most-inaccessible-site-possible-with-a-perfect-lighthouse-score/
slide-74
SLIDE 74 @jessbudd4

Automated testing is just the first step

  • Manuel Matuzovic
slide-75
SLIDE 75 @jessbudd4

Keyboard

slide-76
SLIDE 76 @jessbudd4 Can I see where focus is? Does the tab order make sense? Can I access all required elements? Can I use advanced components? Does my focus move when needed?

What to look for

slide-77
SLIDE 77 @jessbudd4

Screenreader

Voiceover (macOS) NVDA (Windows)

slide-78
SLIDE 78 @jessbudd4

Takeaways

Use Semantic HTML Link form labels with inputs Update page titles on routing Manage keyboard focus Use tooling & test your apps
slide-79
SLIDE 79 @jessbudd4

Go forth and make the web a better place

slide-80
SLIDE 80

Thanks!

Slides at bit.ly/laracon19 @jessbudd4