Accessible Components React
title: "Building Accessible Components in React" weight: 19 description: "Learn patterns for building accessible React components: accordion, tabs, modal, tooltip, autocomplete, and slider with proper HTML, ARIA, keyboard support, focus management, and screen reader testing." date: 2026-06-28 lastmod: 2026-06-28 tags: [accessibility, react]
Building accessible React components means combining semantic HTML, conditional ARIA attributes, keyboard event handling, focus management, and live region announcements into reusable component patterns that enforce accessibility at every instance.
## What You'll Learn
You will build accessible versions of common UI components: accordion, tabs, modal, tooltip, and slider -- following ARIA authoring practices and React best practices.
## Why It Matters
Reusable accessible components are the foundation of an accessible React application. A well-built component library means developers get accessibility for free every time they use a component.
## Real-World Use
A team creates an accessible Modal component with focus trapping, Escape handling, and screen reader announcements. Every modal in the app uses this component. A new developer adds a confirmation modal in 5 minutes, and it is automatically accessible.
## Accessible Component Patterns
```mermaid
flowchart TD
A[Component] --> B[Semantic HTML]
A --> C[ARIA Attributes]
A --> D[Keyboard Support]
A --> E[Focus Management]
A --> F[Screen Reader Support]
Component Examples
Each component follows ARIA authoring practices and includes all accessibility requirements.
function Accordion({ items }) {
const [openIndex, setOpenIndex] = useState(null);
return (
<div>
{items.map((item, index) => {
const isOpen = openIndex === index;
const panelId = `panel-${index}`;
const buttonId = `button-${index}`;
return (
<div key={index}>
<button
id={buttonId}
aria-expanded={isOpen}
aria-controls={panelId}
onClick={() => setOpenIndex(isOpen ? null : index)}
>
{item.title}
</button>
<div
id={panelId}
role="region"
aria-labelledby={buttonId}
hidden={!isOpen}
>
{item.content}
</div>
</div>
);
})}
</div>
);
}
function Tooltip({ text, children }) {
const [visible, setVisible] = useState(false);
const tooltipId = useId();
return (
<span
onMouseEnter={() => setVisible(true)}
onMouseLeave={() => setVisible(false)}
onFocus={() => setVisible(true)}
onBlur={() => setVisible(false)}
>
<span aria-describedby={tooltipId}>
{children}
</span>
{visible && (
<div
id={tooltipId}
role="tooltip"
className="tooltip"
>
{text}
</div>
)}
</span>
);
}
function AccessibleModal({ isOpen, onClose, title, children }) {
const closeRef = useRef(null);
const previousFocus = useRef(null);
const titleId = useId();
useEffect(() => {
if (isOpen) {
previousFocus.current = document.activeElement;
closeRef.current.focus();
} else if (previousFocus.current) {
previousFocus.current.focus();
}
}, [isOpen]);
useEffect(() => {
const handleKey = (e) => {
if (e.key === 'Escape' && isOpen) onClose();
};
document.addEventListener('keydown', handleKey);
return () => document.removeEventListener('keydown', handleKey);
}, [isOpen, onClose]);
if (!isOpen) return null;
return (
<div
role="dialog"
aria-modal="true"
aria-labelledby={titleId}
className="modal-overlay"
>
<div className="modal-content">
<h2 id={titleId}>{title}</h2>
{children}
<button ref={closeRef} onClick={onClose} aria-label="Close modal">
Close
</button>
</div>
</div>
);
}
Common Mistakes
- Building components that work only with mouse
- Not following ARIA authoring practices for specific patterns
- Creating components that are not composable
- Hard-coding ARIA values that should be dynamic
- Not testing components with screen readers
- Building monolithic components that mix multiple patterns
- Ignoring platform-specific accessibility differences
Practice and Challenge
Practice 1: Build an accessible accordion component. Practice 2: Build accessible tabs with keyboard navigation. Practice 3: Build an accessible modal with focus trap. Practice 4: Add a tooltip that works on hover and focus. Practice 5: Build an accessible slider component.
Challenge: Create a React component library with 5 fully accessible components: Accordion, Tabs, Modal, Tooltip, and Slider. Each component must include proper semantic HTML, ARIA attributes, keyboard navigation, focus management, and screen reader support. Test each component with axe-core and a screen reader.
FAQ
Mini Project
Build a complete accessible component library in React with: Accordion, Tabs (tablist, tab, tabpanel), Modal (dialog with focus trap), Tooltip (hover and focus), Slider (arrow keys, Home/End), Menu Button (with dropdown), and Disclosure (expand/collapse). Each component must pass axe-core tests and work with NVDA and VoiceOver.
What's Next
React Aria Components covers using Adobe's React Aria library for accessible components.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro