Accessibility in React: Beyond aria-label
In this article
Adding aria-label everywhere does not make an interface accessible. In compliance-driven projects, what helps most is semantic HTML, keyboard navigation, and clear feedback for screen readers.
I’ve worked on LGPD dashboards, e-commerce, and enterprise portals. These practices matter most for screen reader and keyboard-only users.
1. Semantic HTML before ARIA
The WAI-ARIA rule still holds: if a native element exists, use it.
tsx// ❌ div pretending to be a button
<div role="button" tabIndex={0} onClick={handleClick}>Save</div>
// ✅ real button
<button type="button" onClick={handleClick}>Save</button>
Use <nav>, <main>, <article>, <button>, and headings in order (h1 → h2). Screen readers navigate by landmarks — generic divs break that flow.
2. Visible focus and tab order
Every interactive element needs clear :focus-visible. Do not remove outline without a replacement:
cssbutton:focus-visible {
outline: 3px solid rgba(124, 58, 237, 0.55);
outline-offset: 4px;
}
In modals and menus, trap focus inside the panel and return focus to the opener on close. Test with Tab and Shift+Tab only.
3. Accordions and expandable panels
For FAQ, filters, and menus, the right pattern is:
aria-expandedon the trigger buttonaria-controlspointing to the panel idrole="region"on content witharia-labelledby
tsx<button
aria-expanded={isOpen}
aria-controls="faq-panel-1"
id="faq-trigger-1"
>
Question
</button>
<div id="faq-panel-1" role="region" aria-labelledby="faq-trigger-1">
Answer
</div>
Avoid display: none without thinking about announcements — content must be accessible when open.
4. Live regions for dynamic updates
Search, filters, and toasts should announce what changed:
tsx<div aria-live="polite" aria-atomic="true" className="visually-hidden">
{resultCount === 0 ? 'No results found' : `${resultCount} results`}
</div>
Use polite for normal updates and assertive only for critical errors.
5. Test with tools and keyboard
Automate basics with axe-core or eslint-plugin-jsx-a11y, but validate manually:
- Keyboard-only navigation
- VoiceOver (macOS) or NVDA (Windows)
- Contrast with Lighthouse or DevTools
A well-written aria-label does not fix low contrast or skipped headings.
Conclusion
Accessibility in React is product work: correct HTML, predictable focus, announced states, and continuous testing.
Start with native HTML, prioritize keyboard use, and test with real people when possible. Accessible interfaces tend to be more robust for everyone.




Comments
Sign in with your GitHub account to comment. Comments are public, stored as Discussions on the blog's comments repository.