Patterns
Accessibility Patterns
Advanced patterns for building accessible web applications
Accessibility (a11y) ensures your app works for everyone, including users with disabilities. This section covers advanced patterns beyond basic WCAG compliance.
Why Advanced Accessibility?
Basic: Adding alt text, semantic HTML
Advanced: Screen reader testing, focus management, motion controlImpact:
- 15% of global population has disabilities
- Legal requirements (ADA, Section 508)
- Better UX for everyone
- SEO benefits
Core Principles (WCAG 2.2)
Perceivable
Content must be presentable in ways users can perceive
Operable
Interface must be operable by everyone
Understandable
Content and operation must be understandable
Robust
Content must work with current and future technologies
Coverage
This section includes:
- Screen Reader Testing - NVDA, JAWS, VoiceOver strategies
- ARIA Live Regions - Dynamic content announcements
- Focus Management - SPA focus patterns
- Keyboard Shortcuts - Custom accessible shortcuts
- Accessible Animations - Motion accessibility
- Color Contrast - WCAG AAA compliance
- Complex Forms - Multi-step, conditional forms
Quick Start
// Basic accessible component
export function AccessibleButton({ onClick, children }: Props) {
return (
<button
onClick={onClick}
type="button"
aria-label="Descriptive label"
>
{children}
</button>
);
}
// With keyboard support
export function AccessibleDialog({ isOpen, onClose, children }: Props) {
const dialogRef = useRef<HTMLDivElement>(null);
useEffect(() => {
if (isOpen) {
// Trap focus
const firstFocusable = dialogRef.current?.querySelector('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');
(firstFocusable as HTMLElement)?.focus();
}
}, [isOpen]);
return (
<div
ref={dialogRef}
role="dialog"
aria-modal="true"
aria-labelledby="dialog-title"
>
<h2 id="dialog-title">Dialog Title</h2>
{children}
<button onClick={onClose}>Close</button>
</div>
);
}Testing Tools
# Automated testing
npm install -D axe-core @axe-core/react
# Screen readers
- NVDA (Windows) - Free
- JAWS (Windows) - Commercial
- VoiceOver (Mac/iOS) - Built-in
- TalkBack (Android) - Built-in
# Browser extensions
- axe DevTools
- WAVE
- Accessibility InsightsCommon Patterns
Skip Links
export function SkipLinks() {
return (
<a href="#main-content" className="skip-link">
Skip to main content
</a>
);
}
// CSS
.skip-link {
position: absolute;
top: -40px;
left: 0;
background: #000;
color: #fff;
padding: 8px;
z-index: 100;
}
.skip-link:focus {
top: 0;
}Focus Indicators
/* Clear focus indicators */
*:focus-visible {
outline: 2px solid #0066cc;
outline-offset: 2px;
}
/* Context-specific focus */
button:focus-visible {
outline-color: #0066cc;
}
input:focus-visible {
outline-color: #00aa00;
}Semantic HTML
// ❌ BAD: Div soup
<div onClick={handleClick}>Click me</div>
// ✅ GOOD: Semantic button
<button onClick={handleClick}>Click me</button>
// ❌ BAD: No landmarks
<div id="nav">...</div>
<div id="content">...</div>
// ✅ GOOD: Semantic landmarks
<nav>...</nav>
<main>...</main>
<aside>...</aside>Best Practices
- Use semantic HTML first
- Test with real screen readers
- Keyboard navigation for all features
- Color contrast minimum 4.5:1
- Focus management in SPAs
- ARIA only when HTML isn't enough
- Error messages clear and associated
- Loading states announced
- Form labels always present
- Document language specified
Next Steps
Explore the patterns in this section to build truly accessible applications that work for everyone.