loading...

Accessibility for React Developers

fnoah profile image Noah Fleischmann Originally published at noahfleischmann.com ・6 min read

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 of different contrast ratios
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" />
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

Document language

Screen readers need to know the language of the content on a website to use the correct pronunciation.

<html lang="en"></html>
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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.

Use 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.

Comparison between semantic elements like header, article, figure, and footer versus divs everywhere for a page layout

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>
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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.

Progress bar without any labelling

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>
  );
};
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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

Further readings

Discussion

pic
Editor guide