const{ settings }=useAccessibility()<divdata-high-contrast={settings.highContrast}>{/* Automatically styled via CSS */}</div>
Reduced Motion
constprefersReducedMotion=usePrefersReducedMotion()<motion.divanimate={prefersReducedMotion ? {} : {scale: 1.1}}>{/* No animation if reduced motion */}</motion.div>
๐งช Testing
Quick Manual Test
Keyboard Only: Unplug mouse, navigate with Tab
Screen Reader: Enable NVDA/VoiceOver
High Contrast: Enable in accessibility menu
Zoom: Test at 200% zoom
Mobile: Test touch targets
Automated Test
# Run accessibility tests
pnpm test:a11y
# Check specific file
pnpm test src/components/MyComponent.test.tsx
๐จ Common Mistakes
โ Don't
// Icon without label<button><TrashIcon/></button>// Click handler on div<divonClick={handleClick}>Clickme</div>// Placeholder as label<inputplaceholder="Email"/>// Color-only indicator<spanstyle={{color: 'red'}}>Error</span>// Missing alt text<imgsrc="photo.jpg"/>
โ Do
// Icon with label<buttonaria-label="Delete"><TrashIcon/></button>// Use button element<buttononClick={handleClick}>Clickme</button>// Proper label<labelhtmlFor="email">Email</label><inputid="email"type="email"/>// Icon + text for errors<spanrole="alert"><ErrorIcon/> Error: Invalid input
</span>// Descriptive alt text<imgsrc="photo.jpg"alt="Team photo at 2026 retreat"/>