Accessibility for React Developers
Published on September 29, 2020
Introduction
Accessible websites can be used by everyone, regardless of their abilities. Designing and building accessible websites means ensuring they work with assistive technologies like screen readers or keyboard navigation and for people with color deficiencies. Of course, there are many more disabilities, but these are the most common ones to keep in mind while building your web apps. This article serves as an introduction to accessibility and teaches you the basics of how to build accessible React applications.
Quick Wins
Your React application will eventually render HTML, so it’s not only important that your complex interactive components are accessible, but also you’re basic markup and styling. Even making interactive JavaScript-heavy components accessible mainly consists of improving their markup. But even without considering JavaScript, there are a few things you can do which will already greatly increase the accessibility of your site.
Color contrast
The WCAG 2 spec defines color contrast as the perceived brightness between two colors. This is expressed as a ratio ranging from 1:1 (white text on white background) to 21:1 (black text on white background).
Illustration by Accessible Web.
WCAG recommends to at least have a contrast of 4.5:1 and 3:1 normal text for text larger than 24 pixels, respectively. At least key here. Try to use a contrast that exceeds the minimum requirements. Both Chrome and Firefox developer tools will show an element’s contrast when inspecting it.
Alt attribute
Most likely you’re already familiar with this. The alt attribute describes the content of an image. This description comes in handy if an image doesn’t load correctly, for search engines that index your site, and most importantly for visually impaired users who rely on a screen reader.
<img src="image.jpeg" alt="Birch tree on a meadow" />
Form labels
Use labels for all interactive elements in a form, which are also known as form controls. They help the user understand what the form control does.
// JSX uses htmlFor to associate a label with a form control
<label htmlFor="firstname">First name:</label>
<input type="text" name="firstname" id="firstname"><br>
If you have a form control where the purpose is obvious when rendered visually, such as a search bar, use aria-label
to let screen readers know the purpose of the element.
<input type="text" name="search" aria-label="Search">
<button type="submit">Search</button>
Button text
Buttons, such as icon-only buttons, where the purpose is only obvious when rendered visually should also be described using aria-label
.
<button type="submit" aria-label="Search">
Search
</button>
Document language
Screen readers need to know the language of the content on a website to use the correct pronunciation.
<html lang="en"></html>
If some parts on a page are written in another language than the rest of the content, you can add the lang
attribute to any HTML element which surrounds it.
<span lang="fr">C'est en français</span>
Making interactive components accessible
There are a few extra steps involved in making high fidelity, interactive applications accessible. So once you implemented the aforementioned steps, try to improve the accessibility of your interactive components, like drop-downs, for example.
Using semantic HTML elements
Semantic HTML elements are elements that convey their meaning to both the developer and the browser. This article by W3Schools offers a list of elements considered to be semantic.
Instead of relying on divs for your application layout, use the appropriate semantic elements HTML provides you. This helps screen readers and other tools identify the relevant content.
When developing React applications you have the option to build almost anything using only divs and spans. And while button
or select
elements aren’t officially considered to be semantic HTML elements, they still convey a clearer meaning compared to a div. So instead of making a div an interactive, clickable element, use the proper HTML element, when available. This will save you from having to use lots of ARIA attributes, which we’ll get to later.
<div role="button" tabIndex="0" onClick={clickHandler}>
<!-- Content-->
</div>
// use the HTML button element!
<button onClick={clickHandler}>
Click me
</button>
Keyboard navigation
Keyboard navigation is a huge part of accessibility, but it can also come in handy for anyone else who occasionally likes to navigate a website without touching their mouse. Keyboard navigation works by cycling through each interactive element by pressing tab and activating those elements by pressing enter or space. There are two important factors to consider when making sure keyboard navigation works correctly on your website: making sure every interactive element is reachable and not having custom CSS to hide the border that highlights the selected item. To manage item selection, tabIndex
can be used.
Elements like links or buttons are inside the tab order per default (meaning, they can be reached using tab), so use them wherever possible. Whenever you have a custom interactive component, like a clickable div, you need to consider using tabIndex
because otherwise, your component won’t be reachable for keyboard users
tabIndex = '0'; // in tab order, can be selected
tabIndex = '-1'; // removed from tab order, cannot be selected
tabIndex = '1234'; // manually manage tab order, usually not needed
Interactive HTML elements like links or buttons are inside the tab order per default (meaning, they can be reached using tab), so use them wherever possible. As soon as have a custom interactive component, like a clickable div, you need to start thinking about using tabIndex
because otherwise your component won’t be usable for keyboard users.
ARIA
ARIA is a specification that’s a crucial tool for building accessible web applications. It offers numerous attributes that are used for supplying accessibility information. If you want to develop accessible JavaScript applications, ARIA is arguably the most important technology to use.
Since ARIA is somewhat complex, my recommendation is to use descriptive HTML elements wherever possible. Often, they eliminate the need for ARIA. But there are cases where simply using proper HTML isn’t enough. That’s where ARIA comes into play. ARIA attributes are one of three types: roles, properties, and states.
ARIA attributes are one of three types: roles, properties, and states.
- Role: Defines what an element is and what is does
- State: Describes the state of an element, such as checked for a checkbox
- Property: Additional properties that semantic HTML doesn’t cover
Here’s a list of all ARIA attributes: https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques.
In the next chapter, we’re going to examine how you can use ARIA to make React components more accessible.
Example: Progress Bar
Take a normal progress bar like this one. Now, imagine, how would anyone who relies on a screen reader be able to understand its content? All the information is hidden within the styling, which is useless for a screen reader. The markup could be as little as one empty div.
Thanks to ARIA, we can utilize a few attributes to make this component fully accessible.
const ProgressBar = ({ progress }) => {
// some CSS-in-JS
return (
<div
role="progress-bar" // purpose of this element
aria-valuenow={progress} // current progress value
aria-valuemin="0" // minimum value of progress bar
aria-valuemax="100" // maximum value of progress bar
></div>
);
};
I chose this example because it nicely shows the capabilities of ARIA. But remember how I said to use semantic HTML wherever possible instead of a meaningless div? Turns out HTML5 comes with a progress
element. Since screen readers can cope with default HTML elements, there is no need to add ARIA attributes.
<progress id="progress-bar" value="50" max="100">
50%
</progress>
However, if semantic HTML elements aren’t flexible enough for your particular use-case, nothing is stopping you from building something custom. You just need to put in some extra work to make it accessible. Many popular UI libraries still use divs in combination with ARIA attributes for their progress bars.
Testing
Just like testing every other feature, it is crucial to test accessibility during development. For starters, use some sort of automated test. Google Lighthouse can spot some accessibility issues. Accessibility Insights by Microsoft and other tools that are based on the axe-core engine are also good choices.
While automated tests are a good place to start, you shouldn’t solely rely on them. It is worth it to perform manual checks by using your website the same way someone who relies on accessibility features would. Great places to start are screen readers (like Voice Over on macOS) and testing controls by using only the keyboard.
Ressources
React Libraries
While I believe it’s important to know how to build accessibly React applications from scratch, there are many great tools that can make your life easier by providing customizable components that are accessible by default.
- Reach UI provides a great accessible foundation if you want to have complete control over styling
- Chakra UI is my favorite React component library made even better by its focus on accessibility