Accessibility
Accessible React components: the 12-point checklist
Twelve checks that separate a component that only looks right from one that works with a keyboard and a screen reader. With states and tests.
Key points
- Accessibility is a contract about behaviour, not an attribute you add on top.
- Focus, accessible name and state are the first three things to break.
- Test by keyboard and by contrast, not with axe alone.
An accessible React component is not a component with a few extra aria-* attributes. It is a component that still works when there is no mouse, when contrast is low, when the text is zoomed, and when the state changes.
The 12-point checklist
- 1. Visible focus: a ring of 2–3px, contrast at least 3:1.
- 2. Accessible name: every control has a label, even when it shows only an icon.
- 3. Tab order: it follows the visual order, with no traps.
- 4. Keyboard: Enter/Space activate, Escape closes, arrow keys move where they should.
- 5. State: `aria-pressed`, `aria-expanded` and `aria-selected` describe what is true now.
- 6. Error: `aria-invalid` plus a message linked with `aria-describedby`.
- 7. Live region: asynchronous changes get announced without spam.
- 8. Contrast: 4.5:1 for text, 3:1 for large text and focus rings.
- 9. Tap target: at least 44×44px on touch.
- 10. Zoom: the layout holds at 200% without losing content.
- 11. Reduced motion: every animation has a fallback.
- 12. Real test: keyboard, screen reader and a person, not just axe.
The three most common mistakes
The first is a clickable div: it loses focus, keyboard access and semantics. The second is an icon with no name: the screen reader announces "button" and nothing else. The third is a visual error with no announcement: the message is on screen but never read out.
Where to start
Start with the components a user needs in order to complete an action: button, input, select, dialog, toast. The guides Accessible React buttons and Accessible form validation cover the two entry points that come up most.
Frequently asked questions
Is axe enough for accessibility?
No. Axe catches some static errors, but it does not walk the flow by keyboard or judge whether announcements are useful.
Should I put aria-label on everything?
No. A visible label is better. Use aria-label when the accessible name is not in the visible text.
How do I test with a screen reader?
VoiceOver on macOS, NVDA or Narrator on Windows. Run the main flow, not just the single component.
Is a focus ring mandatory?
Yes, when a control can be reached by keyboard. You can change how it looks, but you cannot remove it without a replacement.
Does accessibility make the design worse?
No, it makes the interface more explicit. Contrast, focus and readable states help everyone, not only people using assistive technology.