Building Accessible React Components: A Comprehensive Guide
Building Accessible React Components: A Comprehensive Guide
Accessibility isn't a feature—it's a fundamental requirement. When we build inaccessible applications, we exclude millions of users who rely on assistive technologies. Let's build better.
The Four Principles of Accessibility
1. Perceivable
Information must be presentable to users in ways they can perceive:
- Provide text alternatives for images
- Offer captions for videos
- Ensure sufficient color contrast
2. Operable
Users must be able to operate the interface:
- Make all functionality keyboard accessible
- Give users enough time to read and interact
- Don't design content that could cause seizures
3. Understandable
Information and operation must be understandable:
- Make text readable and understandable
- Make content appear and operate predictably
- Help users avoid and correct mistakes
4. Robust
Content must be robust enough for various assistive technologies:
- Maximize compatibility with current and future tools
- Use valid, semantic HTML
Building Accessible Components
Semantic HTML First
Always start with semantic HTML:
// Good: Semantic button
<button onClick={handleClick}>
Click me
</button>
// Bad: Non-semantic div
<div onClick={handleClick}>
Click me
</div>
Keyboard Navigation
Every interactive element must be keyboard accessible:
function Dropdown() {
const [isOpen, setIsOpen] = useState(false);
const handleKeyDown = (e) => {
if (e.key === 'Enter' || e.key === ' ') {
setIsOpen(!isOpen);
} else if (e.key === 'Escape') {
setIsOpen(false);
}
};
return (
<div>
<button
onClick={() => setIsOpen(!isOpen)}
onKeyDown={handleKeyDown}
aria-expanded={isOpen}
aria-haspopup="true"
>
Menu
</button>
{/* ... */}
</div>
);
}
ARIA Attributes
Use ARIA to enhance semantics when HTML alone isn't enough:
- aria-label: Provides a label when visible text isn't available
- aria-describedby: References an element that describes the current element
- aria-live: Announces dynamic content changes
- aria-hidden: Hides decorative elements from screen readers
Focus Management
Manage focus appropriately:
function Modal({ isOpen, onClose }) {
const modalRef = useRef();
useEffect(() => {
if (isOpen) {
modalRef.current?.focus();
}
}, [isOpen]);
return (
<dialog
ref={modalRef}
open={isOpen}
aria-modal="true"
onKeyDown={(e) => {
if (e.key === 'Escape') onClose();
}}
>
{/* ... */}
</dialog>
);
}
Testing for Accessibility
Automated Testing
Tools like:
- axe DevTools
- Lighthouse
- pa11y
Manual Testing
- Navigate with keyboard only
- Use a screen reader (VoiceOver, NVDA, JAWS)
- Test with browser zoom at 200%
- Check color contrast
Common Pitfalls
- Relying solely on color: Use multiple visual cues
- Missing alt text: Every image needs descriptive alt text
- Poor focus indicators: Make focus states visible
- Auto-playing media: Let users control playback
- Inaccessible forms: Label inputs properly and provide clear error messages
Conclusion
Accessibility makes the web better for everyone. It's not about checking boxes—it's about empathy and inclusive design. Start small, test often, and always keep your users in mind.
Remember: If your app isn't accessible, it's not finished.