Making Single Page Apps Accessible

A presentation at NDC Sydney 2024 in February 2024 in Sydney NSW, Australia by Jess Budd

Slide 1

Slide 1

Making Single Page Apps Accessible jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 2

Slide 2

JESS BUDD - Senior software engineer - Web accessibility nerd - Lover of lego jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 3

Slide 3

jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 4

Slide 4

TIM BERNERS-LEE Inventor of the World Wide Web jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 5

Slide 5

The power of the web is in its universality. Access by everyone, regardless of disability is an essential aspect. - Tim Berners-Lee jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 6

Slide 6

It doesn’t have to be this way. jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 7

Slide 7

Nothing in React prevents us from building accessible web apps - Leslie Cohn-Wein, Netlify jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 8

Slide 8

jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 9

Slide 9

jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 10

Slide 10

… @jessbudd4 jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 11

Slide 11

Low hanging does not mean low impact. - Samuel Proulx, Accessibility Evangelist, blind since birth jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 12

Slide 12

What is accessibility?

Slide 13

Slide 13

Removing barriers to using your website @jessbudd4 jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 14

Slide 14

Accessibility benefits all of us. jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 15

Slide 15

Image credit: Microsoft Inclusive Design jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 16

Slide 16

Accessibility: otherwise known as A11y jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 17

Slide 17

Visual •285 million worldwide •Blindness •Colour blindness •Low or tunnel vision jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 18

Slide 18

Auditory •1 in 6 Australians •Profound deafness •Hard of hearing jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 19

Slide 19

Motor •Loss of limbs •Chronic pain conditions •Cerebral Palsy jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 20

Slide 20

Cognitive •Intellectual impairments •Learning disabilities •Dementia jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 21

Slide 21

Be kind to your future (old) self. jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 22

Slide 22

Web Content Accessibility Guidelines

Slide 23

Slide 23

WCAG (wuh-cag) jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 24

Slide 24

WCAG (wuh-cag) jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 25

Slide 25

P O U R jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 26

Slide 26

Perceivable O U R jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 27

Slide 27

Perceivable Operable U R jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 28

Slide 28

Perceivable Operable Understandable R jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 29

Slide 29

Perceivable Operable Understandable Robust jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 30

Slide 30

• Level A: bare minimum • Level AA: industry standard to aim for • Level AAA: highest standard jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 31

Slide 31

• Level A: bare minimum • Level AA: industry standard to aim for • Level AAA: highest standard jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 32

Slide 32

HTML

Slide 33

Slide 33

Use native browser elements and controls jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 34

Slide 34

Why does it matter? jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 35

Slide 35

jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 36

Slide 36

Image credit: Microsoft Inclusive Design jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 37

Slide 37

Accessibility is good for SEO jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 38

Slide 38

If a screen reader can’t understand your content, neither can Google. jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 39

Slide 39

// Inaccessible card component <template> <div class=”card”> <div>{{productName}}</div> <div>{{productDescription}}</div> <div v-on:click=”doSomething”> {{buttonText}} </div> </div> </template> jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 40

Slide 40

Click to edit jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 41

Slide 41

<CustomComponent> jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 42

Slide 42

// More accessible card component <template> <li :class=”card”> <h2>{{productName}}</h2> <p>{{productDescription}}</p> <button v-on:click=”doSomething”> {{buttonText}} </button> </li> </template> jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 43

Slide 43

Divs are not buttons. jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 44

Slide 44

<div tabindex=”0” role=”button” v-on:keyup={handleKeyUp} v-on:click={handleClick}> {{buttonText}} </div> jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 45

Slide 45

<div tabindex=”0” role=”button” v-on:keyup={handleKeyUp} v-on:click={handleClick}> {{buttonText}} </div> jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 46

Slide 46

<div tabindex=”0” role=”button” v-on:keyup={handleKeyUp} v-on:click={handleClick}> {{buttonText}} </div> jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 47

Slide 47

<button v-on:click={handleClick}> {{buttonText}} </button> jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 48

Slide 48

Give buttons some love jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 49

Slide 49

WCAG success criteria: 1.3.1 - Info and relationships (A) 2.1.1 - Keyboard (A) 4.1.2 - Name, Role, Value (A) jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 50

Slide 50

FORMS

Slide 51

Slide 51

Inputs must have labels. Labels must be linked. jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 52

Slide 52

// label not linked to input <label> Lego character: </label> <input type=”text” K N A L B , t x e Edit t name=”character” /> jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 53

Slide 53

// explicitly linked label to input <label for=”uniqueId”> Lego character: </label> <input id=”uniqueId” R E T C A R A H C O Edit text, LEG type=”text” name=”character” /> jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 54

Slide 54

How can I make sure my IDs are unique? jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 55

Slide 55

import { v4 as uuid } from “uuid”; <script> data() { return { id: ${this.name}-${uuid()} } } }; </script> <template> <div class=”a11y-input”> <label v-bind:for=”uniqueId”>{{ label }}</label> <input v-bind:id=”uniqueId” v-bind:name=”name” type=”text” /> </div> </template> jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 56

Slide 56

import { v4 as uuid } from “uuid”; <script> data() { return { id: ${this.name}-${uuid()} } } }; </script> <template> <div class=”a11y-input”> <label v-bind:for=”uniqueId”>{{ label }}</label> <input v-bind:id=”uniqueId” v-bind:name=”name” type=”text” /> </div> </template> jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 57

Slide 57

import { v4 as uuid } from “uuid”; <script> data() { return { id: ${this.name}-${uuid()} } } }; </script> <template> <div class=“a11y-input”> <label v-bind:for=”uniqueId”>{{ label }}</label> <input v-bind:id=”uniqueId” v-bind:name=”name” type=”text” /> </div> </template> jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 58

Slide 58

Implicit linking? jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 59

Slide 59

// implicitly linked label to input <label> Lego character: <input type=”text” name=”character” R E T C A R A H C O Edit text, LEG /> </label> jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 60

Slide 60

What if the design doesn’t have labels? jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 61

Slide 61

// label hidden with css is still announced <label class=”sr-only” for=”legoCharacter”> Lego character: </label> <input id=”legoCharacter” type=”text” name=”character” /> jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 62

Slide 62

// visually hidden, but accessible to screen readers .sr-only { clip: rect(0 0 0 0); clip-path: inset(50%); height: 1px; width: 1px; overflow: hidden; position: absolute; white-space: nowrap; } jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 63

Slide 63

WCAG success criteria: 3.3.2 - Labels or instructions (A) jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 64

Slide 64

Can I use placeholders instead? jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 65

Slide 65

Placeholders are not labels jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 66

Slide 66

…or suitable help text jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 67

Slide 67

WCAG success criteria: 3.3.2 - Labels or instructions (A) 3.3.5 - Help (AAA) jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 68

Slide 68

… jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 69

Slide 69

Implicitly linked touch target jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 70

Slide 70

Explicitly linked touch target jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 71

Slide 71

WCAG success criteria: 2.5.8 - Target size (minimum) (AA) 2.5.5 - Target size (AAA) jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 72

Slide 72

Autocomplete jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 73

Slide 73

<label for=”uniqueId”> First name: </label> <input id=”uniqueId” type=”text” name=”firstName” autocomplete=”given-name” /> jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 74

Slide 74

WCAG success criteria: 1.3.5 - Identify input purpose (AA) jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 75

Slide 75

FOCUS STYLES

Slide 76

Slide 76

Image credit:Access Guide jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 77

Slide 77

Safari: Firefox: Chrome: jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 78

Slide 78

Removing the focus outline is like removing the wheelchair ramp from a school because it doesn’t fit the aesthetic. - David Gilbertson jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 79

Slide 79

Meme where am I jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 80

Slide 80

Screen shot of page with masses of ??? links and question marks jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 81

Slide 81

/* don’t just remove */ :focus { outline: none; } / replace with something! */ :focus-visible { / branded focus styles here */ outline: 2px dotted #10ffc3; } jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 82

Slide 82

WCAG success criteria: 1.4.11 - Non-text contrast (AA) 2.4.7 - Focus visible (AA) 2.4.13 - Focus appearance (AAA) jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 83

Slide 83

Make it big and stand out jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 84

Slide 84

Outlines are best jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 85

Slide 85

Offset outlines even better *:focus-visible { outline: 2px dotted #10ffc3; outline-offset: 2px; } jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 86

Slide 86

ROUTING

Slide 87

Slide 87

Traditional multi-page app behaviour Builds the page jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 88

Slide 88

Traditional multi-page app behaviour Builds the page jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 89

Slide 89

Single page app behaviour Builds the page jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 90

Slide 90

Single page app behaviour Builds the page jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 91

Slide 91

Single page app behaviour Builds the page jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 92

Slide 92

  1. Update page title 2. Manage keyboard focus jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 93

Slide 93

PAGE TITLES

Slide 94

Slide 94

PAGE TITLE jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 95

Slide 95

LEGO IS FUN!

<head> MY FAVE LEGO MORE LEGO <meta charset=”utf-8”> <title>Lego is fun!</title> <link rel=”stylesheet” href=”style.css”> </head> jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 96

Slide 96

jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 97

Slide 97

// react functional component import { useEffect } from “react” export const BlogPost = () =>{ useEffect(() => { document.title = “Trolls lego is the best” }) return( <> <h1>A heading</h1> <p>Some page content</p> </> ) } jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 98

Slide 98

// vue page level component <script> export default { name: “Blog post”, mounted() { document.title = “Trolls lego is the best”; }, }; </script> jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 99

Slide 99

const router = new VueRouter({ routes: [ { path: ‘/blog’, component: BlogComponent, meta: { title: “My awesome Lego blog” } }, { path: ‘/about’, component: AboutComponent, meta: { title: “About Lego Lover” } } ] }); jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 100

Slide 100

router.beforeEach((to, from, next) => { document.title = to.meta.title || ‘${defaultTitle}’; next(); }); jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 101

Slide 101

// use helmet to update additional meta data at the same time import {Helmet} from “react-helmet”; export const SignupForm = () =>{ return( react-helmet <Helmet> <title>{meta.title}</title> <meta name=”image” content={meta.image} /> <meta name=”description” content={meta.description}/> <meta name=”og:title” content={meta.title}/> <meta name=”og:description” content={meta.description}/> <meta name=”og:image” content={meta.image}/> </Helmet> vue-meta ) } jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 102

Slide 102

Click to edit jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 103

Slide 103

WCAG success criteria: 2.4.2 - Page titled (A) jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 104

Slide 104

FOCUS MANAGEMENT

Slide 105

Slide 105

Option 1: Fake a traditional navigation jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 106

Slide 106

Option 2: Optimise navigation jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 107

Slide 107

Tabindex tabindex=”0” // makes element focusable in tab/DOM order tabindex=”-1” // makes elements focusable only via scripting tabindex=”5” // danger Will Robinson! jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 108

Slide 108

Tabindex tabindex=”0” // makes element focusable in tab/DOM order tabindex=”-1” // makes elements focusable only via scripting tabindex=”5” // danger Will Robinson! jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 109

Slide 109

Tabindex tabindex=”0” // makes element focusable in tab/DOM order tabindex=”-1” // makes elements focusable only via scripting tabindex=”5” // danger Will Robinson! jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 110

Slide 110

Tabindex tabindex=”0” // makes element focusable in tab/DOM order tabindex=”-1” // makes elements focusable only via scripting tabindex=”5” // danger Will Robinson! jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 111

Slide 111

import React, { useEffect, useRef } from ‘react’; const PageComponent = () => { const h1Ref = useRef(null); useEffect(() => { if (h1Ref.current) { h1Ref.current.focus(); } }, []); return ( <h1 ref={h1Ref} tabIndex=”-1”>Lego is the best!</h1> // Rest of the component ); }; jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 112

Slide 112

import React, { useEffect, useRef } from ‘react’; const PageComponent = () => { const h1Ref = useRef(null); useEffect(() => { if (h1Ref.current) { h1Ref.current.focus(); } }, []); return ( <h1 ref={h1Ref} tabIndex=”-1”>Lego is the best!</h1> // Rest of the component ); }; jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 113

Slide 113

import React, { useEffect, useRef } from ‘react’; const PageComponent = () => { const h1Ref = useRef(null); useEffect(() => { if (h1Ref.current) { h1Ref.current.focus(); } }, []); return ( <h1 ref={h1Ref} tabIndex=”-1”>Lego is the best!</h1> // Rest of the component ); }; jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 114

Slide 114

jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 115

Slide 115

// don’t show focus for headings H1:focus-visible { outline: none; } jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 116

Slide 116

MODALS

Slide 117

Slide 117

jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 118

Slide 118

Modals are actually the boss battle at the end of web accessibility. - Rob Dodson, host of A11yCasts jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 119

Slide 119

jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 120

Slide 120

<script> export default { methods: { showDialog() { this.$refs.dialogRef.showModal(); }, closeDialog() { this.$refs.dialogRef.close(); }, }, }; </script> <template> <dialog ref=”dialogRef”> <button v-on:click=”closeDialog”>Close</button> <p>Modal content</p> </dialog> <button v-on:click=”showDialog”>Show the dialog</button> </template>

jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 121

Slide 121

<script> export default { methods: { showDialog() { this.$refs.dialogRef.showModal(); }, closeDialog() { this.$refs.dialogRef.close(); }, }, }; </script> <template> <dialog ref=”dialogRef”> <button v-on:click=”closeDialog”>Close</button> <p>Modal content</p> </dialog> <button v-on:click=”showDialog”>Show the dialog</button> </template>

jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 122

Slide 122

jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 123

Slide 123

// send focus to non-destructive button <dialog> <h2>Delete Conversation</h2> <p>Are you sure you want to delete this conversation? This action cannot be undone.</p> <button>{{destructiveAction}}</button> <button autofocus>{{cancel}}</button> </dialog> jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 124

Slide 124

:modal { border: 5px solid red; background-color: yellow; box-shadow: 3px 3px 10px rgb(0 0 0 / 50%); } ::backdrop { background: rebeccapurple; opacity: 0.75; } jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 125

Slide 125

:modal { border: 5px solid red; background-color: yellow; box-shadow: 3px 3px 10px rgb(0 0 0 / 50%); } ::backdrop { background: rebeccapurple; opacity: 0.75; } jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 126

Slide 126

html inert attribute jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 127

Slide 127

inert 102 jessbudd@bsky.social 102 jessbudd@front-end.social 112 15.5 jessbudd44 19 @jessbudd @jessbudd4

Slide 128

Slide 128

WCAG success criteria: 2.4.3 - Focus order (AA) jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 129

Slide 129

TESTING

Slide 130

Slide 130

Automated + Manual jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 131

Slide 131

jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 132

Slide 132

Automated jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 133

Slide 133

jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 134

Slide 134

“I need to learn about accessibility and need to write code that conforms with the WCAG 2.1 level A and AA success criteria de ned at https:// www.w3.org/TR/WCAG21/. I want you to be my accessibility coach, a subject-matter expert that makes me think and account for all accessibility requirements and usability enhancements. When you answer questions about accessibility please use reputable sources such as w3.org, webaim.org, developer.mozilla.org, and https:// www.ibm.com/able/. When possible, please provide links and references for additional learning. When you suggest code please use semantic HTML, ensure it is operable using the keyboard, follow WCAG 2.1 su cient techniques, and follow the ARIA Authoring Practices Guide and related design patterns. Do you understand these instructions?” jessbudd@front-end.social jessbudd44 @jessbudd fi ffi jessbudd@bsky.social @jessbudd4

Slide 135

Slide 135

“I need to learn about accessibility and need to write code that conforms with the WCAG 2.1 level A and AA success criteria de ned at https:// www.w3.org/TR/WCAG21/. I want you to be my accessibility coach, a subject-matter expert that makes me think and account for all accessibility requirements and usability enhancements. When you answer questions about accessibility please use reputable sources such as w3.org, webaim.org, developer.mozilla.org, and https:// www.ibm.com/able/. When possible, please provide links and references for additional learning. When you suggest code please use semantic HTML, ensure it is operable using the keyboard, follow WCAG 2.1 su cient techniques, and follow the ARIA Authoring Practices Guide and related design patterns. Do you understand these instructions?” jessbudd@front-end.social jessbudd44 @jessbudd fi ffi jessbudd@bsky.social @jessbudd4

Slide 136

Slide 136

“I need to learn about accessibility and need to write code that conforms with the WCAG 2.1 level A and AA success criteria de ned at https:// www.w3.org/TR/WCAG21/. I want you to be my accessibility coach, a subject-matter expert that makes me think and account for all accessibility requirements and usability enhancements. When you answer questions about accessibility please use reputable sources such as w3.org, webaim.org, developer.mozilla.org, and https:// www.ibm.com/able/. When possible, please provide links and references for additional learning. When you suggest code please use semantic HTML, ensure it is operable using the keyboard, follow WCAG 2.1 su cient techniques, and follow the ARIA Authoring Practices Guide and related design patterns. Do you understand these instructions?” jessbudd@front-end.social jessbudd44 @jessbudd fi ffi jessbudd@bsky.social @jessbudd4

Slide 137

Slide 137

“I need to learn about accessibility and need to write code that conforms with the WCAG 2.1 level A and AA success criteria de ned at https:// www.w3.org/TR/WCAG21/. I want you to be my accessibility coach, a subject-matter expert that makes me think and account for all accessibility requirements and usability enhancements. When you answer questions about accessibility please use reputable sources such as w3.org, webaim.org, developer.mozilla.org, and https:// www.ibm.com/able/. When possible, please provide links and references for additional learning. When you suggest code please use semantic HTML, ensure it is operable using the keyboard, follow WCAG 2.1 su cient techniques, and follow the ARIA Authoring Practices Guide and related design patterns. Do you understand these instructions?” jessbudd@front-end.social jessbudd44 @jessbudd fi ffi jessbudd@bsky.social @jessbudd4

Slide 138

Slide 138

“I need to learn about accessibility and need to write code that conforms with the WCAG 2.1 level A and AA success criteria de ned at https:// www.w3.org/TR/WCAG21/. I want you to be my accessibility coach, a subject-matter expert that makes me think and account for all accessibility requirements and usability enhancements. When you answer questions about accessibility please use reputable sources such as w3.org, webaim.org, developer.mozilla.org, and https:// www.ibm.com/able/. When possible, please provide links and references for additional learning. When you suggest code please use semantic HTML, ensure it is operable using the keyboard, follow WCAG 2.1 su cient techniques, and follow the ARIA Authoring Practices Guide and related design patterns. Do you understand these instructions?” jessbudd@front-end.social jessbudd44 @jessbudd fi ffi jessbudd@bsky.social @jessbudd4

Slide 139

Slide 139

“I need to learn about accessibility and need to write code that conforms with the WCAG 2.1 level A and AA success criteria de ned at https:// www.w3.org/TR/WCAG21/. I want you to be my accessibility coach, a subject-matter expert that makes me think and account for all accessibility requirements and usability enhancements. When you answer questions about accessibility please use reputable sources such as w3.org, webaim.org, developer.mozilla.org, and https:// www.ibm.com/able/. When possible, please provide links and references for additional learning. When you suggest code please use semantic HTML, ensure it is operable using the keyboard, follow WCAG 2.1 su cient techniques, and follow the ARIA Authoring Practices Guide and related design patterns. Do you understand these instructions?” jessbudd@front-end.social jessbudd44 @jessbudd fi ffi jessbudd@bsky.social @jessbudd4

Slide 140

Slide 140

Are you still using the instructions I provided? jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 141

Slide 141

eslint-plugin-jsx-a11y jessbudd@bsky.social jessbudd@front-end.social eslint-plugin-vuejs-accessibility jessbudd44 @jessbudd @jessbudd4

Slide 142

Slide 142

•Images have alt text •Links have accessible content •Mouse events have key events •Labels have “for” attributes •…and more jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 143

Slide 143

react-axe jessbudd@bsky.social jessbudd@front-end.social Vue-axe jessbudd44 @jessbudd @jessbudd4

Slide 144

Slide 144

jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 145

Slide 145

jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 146

Slide 146

jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 147

Slide 147

jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 148

Slide 148

jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 149

Slide 149

Click to edit jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 150

Slide 150

Automated testing is just the first step jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 151

Slide 151

Manual jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 152

Slide 152

jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 153

Slide 153

What to look for Can I see where the focus is? Does the tab order make sense? Can I get to all the components? Can all interactive components be activated? jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 154

Slide 154

Screen readers jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 155

Slide 155

Source: 2021 WebAim screen reader survey #9 VoiceOver JAWS 6.5% 53.7% NVDA 30.7% jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 156

Slide 156

Click to edit

Slide 157

Slide 157

VoiceOver TalkBack jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 158

Slide 158

TalkBack 29% VoiceOver 71% Source: 2021 WebAim screen reader survey #9

Slide 159

Slide 159

What to look for Are all buttons announced correctly? Does link text make sense out of context? Are form labels announced? Announcement of component state jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 160

Slide 160

Summary Using the right HTML Link form labels with inputs Update page titles on routing Manage keyboard focus and make it visible Test your apps jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 161

Slide 161

Final thought… jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 162

Slide 162

The web does not just connect machines, it connects people. - Tim Berners-Lee jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4

Slide 163

Slide 163

resources THANK YOU bit.ly/ndcSydney24 jessbudd@bsky.social jessbudd@front-end.social jessbudd44 @jessbudd @jessbudd4