Let's make an accessible component
- 
	
git clone https://github.com/ericmasiello/accessibility-demo.git - 
	
cd accessibility-demo - 
	
npm install 
This is how you're doing it wrong.
(Demo)
Tabbed interface
- Visual presentation
 - Visual behavior
 - Keyboard behavior
 
Tabs are not a native web paradigm. They come from desktop interfaces.
Goals
- Retain the expected visual design
 - Operable via non-pointer/touch input
 - Operable and understandable by screen reader
 
The Plan
- Review existing code
 - Implement basic keyboard support
 - Implement expected tab interface behaviors
 - Implement easy HTML wins
 - Improve screen reader support
 
Starter HTML (JSX)
<div className="tablist">
<div className="tab">Tab name</div>
...
</div>
- Interactive elements should be keyboard focusable
 - How can we make the "tab" keyboard focusable?
 
That was easy
<div className="tablist">
  <div className="tab">Tab name</div>
<button className="tab">Tab name</button>
...
</div>
git checkout 02-basic-keyboard-focus
Don’t forget focus states
- Users who rely on non pointer/touch input (e.g. keyboard) rely on focus states to know where they are in the interface.
 - Like many AX considerations, these affordances often benefit the non-disabled
 
button:focus,
a:focus {
/* Don't do this without adding back a focus state! */
outline: none;
}
How should a tabbed interface work?
https://www.w3.org/TR/wai-aria-practices/#tabpanel
- Left and Right arrow keys move between tabs
 - Tab key and down arrow key should move focus from selected tab to tab panel (content)
 - Shift + Tab move focus from tab panel back to selected tab
 
problems to solve
- Take non-selected tabs out of the normal tab flow
 - Make the tab panel focusable
 - Pressing the left or right arrow key will select the adjacent tab and set focus on it
 
House keeping: <TabManager />
- Move selected state management up from <Tabs /> to <TabManager />
 - Maintain ref for selected tab
 - Maintain ref for tab panel
 - onKeyDown methods for left, right, and down arrow keys
 - Expose data (state), refs, and keyboard event handlers via render props
 
git checkout 03-proper-tab-keyboard-controls
Tab focus and behavior
{diamonddogs.map(member => ( <button tabIndex={tabState.selected !== member.id ? -1 : undefined} ref={tabState.selected === member.id && tabState.selectedTabRef} onKeyDown={tabState.handleTabKeyDown} onClick={() => { tabState.setSelected(member.id); }} className={classNames(['tab', {'tab--selected': tabState.selected === member.id }])} > {member.name} </button> ))}
Manage Tab Panel Focus
<section ref={tabState.panelRef} tabIndex={0}>
 ...
</section>
Keyboard Events
handleKeyDown = event => { switch (event.which) { case KEYS.right: { this.setState({ selected: findNext( this.props.tabIds, this.state.selected ) }, () => { this.state.selectedTabRef.current.focus(); }); break; } case KEYS.left: { // ...
Keyboard Events
handleKeyDown = event => { switch (event.which) { // ... case KEYS.down: { this.state.panelRef.current.focus(); break;
   // ...
What about screen readers?
MacOS voiceover
- Cmd + Fn + F5: Turn on/off VO
 - Ctrl + Option + A: Start reading
 - Ctrl: Stop reading
 - Ctrl + Option + Right: Read next
 - Ctrl + Option + Right: Read previous
 
Back to Basic HTML
- 
	
<title>Diamond Dog Team Page</title>
 - 
	
<h1 className="page-title">Diamond Dogs</h1>
 - 
	
<img
className="bio-photo"
src={selectedMember.photo}
alt={selectedMember.photoDesc}
/>
 
git checkout 04-additional-html-semantics
marking up the bio
<dl className="bio"> <dt className="bio__label">Hometown</dt> <dd className="bio__item">{selectedMember.hometown}</dd> <dt className="bio__label">Time at Vistaprint</dt> <dd className="bio__item">{selectedMember.employment}</dd> <dt style={{ display: "none" }}>Biography</dt> <dd className="bio__item">{selectedMember.bio}</dd> </dl>
Visually hidden / Announced by Screen readers
<dt style={{ display: "none" }}>Biography</dt>
display: none; is not announced by screen reader
Visually hidden / Announced by Screen readers
<dt className="visually-hidden">Biography</dt>
.visually-hidden {
 border: 0;
 clip: rect(0 0 0 0);
 height: 1px;
 margin: -1px;
 overflow: hidden;
 padding: 0;
 position: absolute;
 width: 1px;
 white-space: nowrap;
}
Still not enough
HTML lacks all the necessary elements to accurately describe our app to assistive technology
ARIA
Accessible Rich Internet Applications: supplements HTML with additional roles, attributes, and states to describe UI widgets
https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA
Tab List
<div role="tablist" className="tablist" aria-label="Team members">
git checkout 05-aria
Tab
<button
 role="tab"
 aria-selected={tabState.selected === member.id}
 aria-controls={tabState.selected === member.id
  ? 'tab-panel'
  : undefined
 }
 ...
Tab Panel
<section
 ref={tabState.panelRef}
 id="tab-panel"
 tabIndex={0}
 role="tabpanel"
 aria-label={selectedMember.name}
>
Accessibility helps everyone

There’s really no right or wrong in inclusive design. It’s just about trying your hardest to provide a valuable experience to as many people as you can... no matter how they are operating or reading your interface...
Did we do it?
Other considerations:
- Cognitive disabilities
 - Visual impairments (e.g. low vision, color blindness)
 
References
Let's make an accessible component
By Eric Masiello
Let's make an accessible component
- 1,364