Accessibility (a11y) in React
5 questions foundWhat is accessibility in React and why does it matter?
Beginner Accessibility means building an app that everyone can use, including people who use screen readers, keyboards only, or have vision or motor difficulties. In React this means using semantic HTML elements, adding proper labels to form fields, and making sure every interactive element can be reached and used with a keyboard.
function LoginForm() {
return (
<form>
<label htmlFor="email">Email</label>
<input id="email" type="email" name="email" />
<button type="submit">Log In</button>
</form>
);
}
Real-world example A banking website adds proper labels and keyboard support to every form so that a visually impaired customer using a screen reader can open an account without needing help from anyone else.
Common follow-ups: What happens if a form input has no label at all?;How do you test a React app for accessibility issues?
Components & JSX;Forms: Controlled & Uncontrolled Components
How do ARIA attributes help improve accessibility in a React component?
Intermediate ARIA attributes give extra information to screen readers when plain HTML is not enough to describe what an element does. For example, aria label describes a button that only has an icon, and aria expanded tells a screen reader whether a menu is open or closed. ARIA should only be used when semantic HTML alone cannot express the meaning.
function MenuButton({ isOpen, onClick }) {
return (
<button aria-expanded={isOpen} aria-label="Open navigation menu" onClick={onClick}>
<MenuIcon />
</button>
);
}
Real-world example A shopping app adds aria expanded to its dropdown filter menu so screen reader users know whether the filter options are currently showing or hidden.
Common follow-ups: When should you avoid using ARIA attributes instead of native HTML elements?;What is the difference between aria label and aria labelledby?
Components & JSX;React DevTools & Debugging
How do you make a custom React component keyboard accessible?
Intermediate A custom component built from a div or span does not get keyboard behavior automatically the way a real button does. To fix this you add tabIndex so it can be focused, and an onKeyDown handler so pressing Enter or Space triggers the same action as a click.
function CustomButton({ onClick, children }) {
return (
<div
role="button"
tabIndex={0}
onClick={onClick}
onKeyDown={(e) => {
if (e.key === 'Enter' || e.key === ' ') onClick();
}}
>
{children}
</div>
);
}
Real-world example A design team builds a custom styled button using a div for a unique look, and adds keyboard support so users who cannot use a mouse can still activate it with the Enter key.
Common follow-ups: Why is it usually simpler to just use a real button element instead of building a custom one?;How do you manage focus order across a whole page?
Components & JSX;Hooks
How would you manage focus properly in a React modal to keep it accessible?
Advanced When a modal opens, focus should move into the modal automatically, and it should stay trapped inside the modal while it is open so a keyboard user cannot accidentally tab to content behind it. When the modal closes, focus should return to the element that opened it.
function Modal({ isOpen, onClose, children }) {
const modalRef = useRef(null);
useEffect(() => {
if (isOpen) modalRef.current?.focus();
}, [isOpen]);
if (!isOpen) return null;
return (
<div ref={modalRef} tabIndex={-1} role="dialog" aria-modal="true">
{children}
<button onClick={onClose}>Close</button>
</div>
);
}
Real-world example A checkout page traps keyboard focus inside its payment confirmation modal so a user pressing Tab repeatedly stays inside the dialog instead of jumping back to the page behind it.
Common follow-ups: How would you build a full focus trap that also cycles back to the first element after the last one?;What role and aria attributes are expected on a modal dialog?
Refs useRef & forwardRef;Effects & Lifecycle
What tools can you use to check accessibility issues in a React app?
Beginner The eslint plugin jsx a11y catches common accessibility mistakes right inside your code editor while you type. The axe DevTools browser extension and Lighthouse in Chrome scan a running page and list real accessibility problems along with clear suggestions on how to fix each one.
// .eslintrc.js
module.exports = {
extends: ['plugin:jsx-a11y/recommended'],
};
// This will now show a warning during development:
// <img src="logo.png" /> // missing alt text
Real-world example A team adds the jsx a11y eslint plugin to their project so that any pull request adding an image without alt text fails automatically before it ever reaches production.
Common follow-ups: How does automated accessibility testing differ from testing with a real screen reader?;What accessibility score does Lighthouse usually flag first for a new React project?
Testing;Build Tools & Bundlers (Vite Webpack & CRA)