Coding for Accessibility: Interactions & Mechanics with JavaScript [3/6]
Hey, there!
Have you ever tried navigating the web with only a keyboard and discovered how inaccessible many websites and web applications are? From online banking and shopping to work/productivity and entertainment apps, lack of keyboard access is way more than an inconvenience for many users. A digital experience built without keyboard support or visible focus outlines will present barriers to people who can't use a mouse or trackpad, effectively shutting them out from using it. This discriminatory practice is a common problem in the field of technology. But, it doesn't have to be this way.
When our sites and apps support the keyboard with focusable and visible elements, JavaScript events, and proper ARIA attributes, they can enable people with disabilities to complete more tasks and improve their online experience.
In this email, you'll learn the ins and outs of keyboard interactions and mechanics using the web platform. You'll also learn where screen reader support overlaps and what to look out for in testing. With this knowledge and a development workflow to match, you'll be able to produce more interactive, robust sites and apps. Pretty cool!
Leverage HTML + JavaScript
The foundation of keyboard accessibility is HTML. As stated previously in this series, it's important to choose elements for their built-in features whenever possible: this includes focusability. Elements such as
<button>, <a href="">, <input>, <textarea>, and <summary> are focusable (also referred to as "reachable") by default, without the need for extra attributes.If for some reason you need to create a custom interactive control after exhausting all built-in HTML options, you can make it keyboard focusable with the
tabindex attribute. A tabindex value of 0 will add an element to the page's tab order according to its place in the DOM, and a value of -1 will remove it from the manual tab order while still making it focusable by script. Beware of using positive integer values of 1 and higher for tabindex, as they will impact the overall tab order and you'll have to manage the page in its entirety. This can prompt such classics as "why is that footer link being focused before everything else?" Inspect your page for tabindex values and find out.A common gotcha when learning about accessibility is that not every element needs to be keyboard-interactive. Screen readers have dedicated commands for headings and landmarks (among other things), so tabindex isn't necessary for those items. Complex interactive widgets with multiple element parts can also benefit from JavaScript techniques like roving tabindex, with one focusable tab stop and arrow key support for the rest of the control. Consider a virtual number pad or calendar, which would exhaust users from completing tasks if built entirely with extra tab stops and no associated text input. "Why do I have to tab through 36 years of days on a calendar to provide my birthdate?" Talk about a poor keyboard user experience.
Tip: take the No Mouse Challenge and work without a mouse or trackpad each week to ensure UIs are reachable and operable from the keyboard. The No Mouse Days package could help to prevent you from cheating.
Another major component in keyboard access is JavaScript events. You can bind callback functions with the event object parameter and listen for specific keys like Escape, Enter, or the Arrow keys:
document.addEventListener('keyup', (event) => { if (event.key === 'Escape' && widget.classList.contains('active')) { widget.classList.remove('active') launchingButton.focus() } })Supporting multiple input modalities for your components (touch, mouse pointer, and keyboard) requires JavaScript code to listen for events and invoke callback functions appropriately. One thing to note is that a native
<button> element will fire a click event from the Enter key, but a <div role="button"> element will not. For custom controls built with DIVs, you will need to bind keyup and mouseup events to ensure keyboard access works along with the mouse.<button>Button 1</button><div tabindex="0" role="button">Button 2</div>var clickHandler = (event) => {
// button will fire from keyboard, DIV will not
console.log(event.target)
}
var keyHandler = (event) => {
// listen for specific keys/combinations
console.log(event.key)
} Don't reinvent the wheel for interactions
There are some established conventions with keyboard access, such as binding the Escape key to close a dialog and return to a triggering button element. Before trying to invent patterns for keyboard access based on a new design that was passed to you, do some research on common conventions using the W3C's ARIA Authoring Practices Guide and/or Inclusive Components from Heydon Pickering. There's the possibility that if you tweak a design to look and function more like a standard component, you'll be able to leverage common navigation paradigms and make the interface more intuitive to users.
Support keyboards and assistive technologies
Keyboard support has some overlap with assistive technologies: for example, focusable components can also be reached with a screen reader running. One big difference between keyboard support and screen readers is the effect of semantic HTML and ARIA on how components operate. A DIV with only
tabindex="0" will be reachable with the keyboard in all cases but role="button" would communicate its purpose and enable JavaScript events to work properly. (A button element would be reachable and announced as a button in screen readers by default.)If you've ever encountered a compound widget like a custom listbox that worked with the keyboard but not with JAWS or NVDA running on Windows, a mismatch could have been caused by incorrect or missing accessibility attributes. That's why it's important to test your components with screen readers in addition to the keyboard, so you know they will work for users of assistive technology. Read about screen reader modes to better understand how semantic HTML and ARIA can affect the usability of a page.
Put users in control
It can be difficult to support every user's preferences with a single website or web application. Take visible focus styles, for example: mouse users love to hate them, while keyboard and voice users need to see their focus point on the screen to know what's happening.
Where focus styling for custom components and multiple input modes has been painful in the past, newer technologies like CSS
:focus-visible can be helpful for providing specific styles for the mouse and keyboard. The :focus-visible API is still trying to guess what users need programmatically, though, which is still difficult to get right 100% of the time. What if users told you what they prefer, instead? Preferences and accessibility settings could be exposed in a web application so the interface adapts to peoples' needs.Accommodating users' needs with optional settings is one thing, but allowing enough time is another entirely. Don't assume all users will see something flashing across the screen before going away automatically, such as a Toast or other notification. Keep dialogs and other temporary layers on screen until the user has time to navigate to them with the keyboard and close by activating a button to confirm, close, or some other intentional action.
Check your understanding of interactions & mechanics by answering a quick question, and I'll send the next email right away.
Talk to you soon,
Marcy Sutton
Marcy Sutton
130 Nickerson St. Suite 207, Seattle, WA 98109