Building an accessible React application means designing a site that everyone, including people with disabilities, can use and enjoy. Accessibility in web apps isn’t just a legal or ethical responsibility—it’s also a best practice that improves user experience for everyone. React, with its dynamic and component-based nature, offers much flexibility, but without careful planning, accessibility can fall through the cracks. This guide will walk you through critical practices to build a more accessible React app, covering essential tools, effective HTML and ARIA usage, keyboard accessibility, and screen reader management.
Why Accessibility in React Matters
An accessible React app does not create obstacles for people who rely on assistive technology like screen readers, keyboards, or other devices. According to Web Content Accessibility Guidelines (WCAG), making web content accessible means people of all abilities can navigate, understand, and interact with your content. With tools and techniques tailored for React, you can ensure that users with disabilities get the best experience possible.
Setting Up an Accessibility-Friendly Development Environment
Setting up your React environment to catch accessibility issues early is a powerful way to build accessible applications. A highly recommended tool for React is eslint-plugin-jsx-a11y, which catches JSX-specific accessibility issues directly in your code editor.
Installing eslint-plugin-jsx-a11y
Install the plugin:
npm install eslint-plugin-jsx-a11y --save-dev
Configure ESLint
: Add the plugin to your ESLint configuration file.
{
"plugins": ["jsx-a11y"],
"extends": [
"eslint:recommended",
"plugin:jsx-a11y/recommended"
]
}
This plugin identifies accessibility issues in JSX, such as missing ARIA roles, empty <alt>
attributes on images, and improper keyboard handling.
The Power of Semantic HTML in React
When it comes to accessibility, semantic HTML is your best friend. Semantic elements like <button>
, <header>
, and <nav>
are designed to convey meaning and functionality to both browsers and screen readers. This minimizes the need for ARIA roles and additional attributes, as semantic HTML elements come with built-in keyboard accessibility and screen reader support.
Examples of Semantic HTML in React
Using semantic elements directly in React makes components accessible by default. For example:
import React from 'react';
function AppHeader() {
return (
<header>
<h1>Welcome to My Store</h1>
<nav>
<a href="#home">Home</a>
<a href="#products">Products</a>
<a href="#contact">Contact</a>
</nav>
</header>
);
}
export default AppHeader;
Avoid Using <div>
and <span>
for Interactive Elements
Avoid using generic elements like <div>
and <span>
to create buttons or links, as these don’t include native keyboard or accessibility functionality. Instead, use <button>
and <a>
elements to ensure proper accessibility and functionality. For example:
function IconButton() {
return <button aria-label="Open settings" onClick={() => alert('Settings')}>⚙️</button>;
}
Enhancing Accessibility with ARIA Roles (But Use Them Wisely)
ARIA (Accessible Rich Internet Applications) can make custom elements accessible when there’s no HTML equivalent. However, it’s essential to use ARIA roles to enhance existing semantic elements rather than replace them.
Using aria-label
for Accessibility
Sometimes, buttons or icons need additional context for screen readers. The aria-label attribute provides descriptive text to communicate functionality.
function IconButton() {
return <button aria-label="Open settings" onClick={() => alert('Settings')}>⚙️</button>;
}
Dynamic Updates with aria-live
React apps often have dynamic content. Use aria-live regions to notify screen readers about important changes.
function AlertMessage({ message }) {
return (
<div aria-live="assertive">
{message}
</div>
);
}
Keyboard Accessibility and Focus Management
Keyboard accessibility ensures users can navigate your app without a mouse, which is crucial for many assistive technology users. In React, managing keyboard focus is straightforward with hooks like useRef
and useEffect
.
Setting Focus with useRef and useEffect
You can use useRef
to target an element and useEffect
to set focus when a component mounts. This is useful for elements like modals, which should receive focus when they appear.
import React, { useRef, useEffect } from 'react';
function Modal({ isOpen, onClose }) {
const closeButtonRef = useRef(null);
useEffect(() => {
if (isOpen) {
closeButtonRef.current.focus();
}
}, [isOpen]);
return (
isOpen && (
<div role="dialog" aria-modal="true">
<p>Modal content here</p>
<button ref={closeButtonRef} onClick={onClose}>Close</button>
</div>
)
);
}
In this example, the close button gains focus when the modal opens, making navigation intuitive for keyboard users.
Avoiding Focus Traps
Focus traps occur when users get “stuck” within an element, such as a modal, and can’t return to the main content. Ensure that focus can move freely between interactive elements and provide a way to close modals with the Escape key.
Best Practices for Accessible Interactive Elements
When building custom components, pay attention to how they’ll be used with a keyboard:
Provide Clear Labels for Inputs
Forms are essential in any application, and labeling form controls is critical for accessibility. Use labels effectively with inputs, either through <label>
elements or aria-label
attributes.
function NameInput() {
return (
<label htmlFor="name">
Name:
<input type="text" id="name" aria-required="true" />
</label>
);
}
Accessible Modals
For custom modal components, set the role= "dialog"
and aria-modal= "true"
attributes, which inform assistive technology that the content is a modal.
Testing Focus
After adding interactive elements, test that each one can be reached and activated using only the Tab, Enter, and Escape keys. This ensures full keyboard accessibility.
Managing Screen Reader Navigation in SPAs
Single Page Applications (SPAs) often update content dynamically without full page reloads, which can make it difficult for screen reader users to keep track of changes. When the main content area updates, shift focus to the new content or provide a way for screen readers to be alerted about the change.
Example: Setting Focus on Page Updates
import React, { useEffect, useRef } from 'react';
function ContentArea({ content }) {
const contentRef = useRef();
useEffect(() => {
contentRef.current.focus();
}, [content]);
return (
<main tabIndex="-1" ref={contentRef}>
{content}
</main>
);
}
Here, the main content area receives focus after each update, helping screen reader users navigate SPAs more easily.
Testing Your React App for Accessibility
Testing is crucial to ensure your React application meets accessibility standards. Here are some testing methods and tools:
- Manual Testing: Use keyboard-only navigation to interact with your app, checking that all elements are accessible and usable. Verify that custom elements respond to the Tab, Enter, and Escape keys.
- Screen Readers: Test with a screen reader like NVDA (for Windows) or VoiceOver (for macOS). Experience the app as a screen reader user to see how well content updates and ARIA roles are conveyed.
- Automated Tools: Tools like Google Lighthouse or WAVE identify many accessibility issues. They’re helpful for quickly checking common problems, although they don’t replace manual testing.
Conclusion
Building accessible React applications takes effort but is entirely achievable with the right techniques and tools. Start by setting up your development environment with eslint-plugin-jsx-a11y
to catch common issues, and always prioritize semantic HTML elements for inherent accessibility. ARIA roles are powerful but should be used to enhance—not replace—standard HTML.
Ensuring keyboard accessibility, managing focus in SPAs, and regularly testing for accessibility can make a world of difference for users. By following these practices, you’re not only meeting WCAG standards but also creating a better user experience for everyone.
Need help? Reach out to 216digital using the contact form below for a complimentary ADA briefing.