Accessibility
Matrix UI components are built with accessibility as a core principle, following WAI-ARIA guidelines.
Built-in Features
Radix UI Foundation
All interactive components inherit accessibility features from Radix UI:
- WAI-ARIA compliant patterns
- Keyboard navigation support
- Focus management and trapping
- Screen reader announcements
- Roving tabindex for composite widgets
ARIA Attributes
Components automatically include appropriate ARIA attributes:
// Alert component <div role="alert" aria-live="polite"> Alert content </div> // Button component <button aria-busy={loading} aria-disabled={disabled} aria-pressed={pressed} > Button text </button> // Dialog component <div role="dialog" aria-modal="true" aria-labelledby="dialog-title" aria-describedby="dialog-description" >
Keyboard Navigation
Standard Patterns
All components follow standard keyboard interaction patterns:
- Tab - Navigate between focusable elements
- Shift + Tab - Navigate backwards
- Enter / Space - Activate buttons and links
- Escape - Close overlays and cancel operations
- Arrow Keys - Navigate within composite widgets
Component-Specific Navigation
Dropdown Menu
- ↓ / ↑ - Navigate menu items
- → - Open submenu
- ← - Close submenu
- Home / End - Jump to first/last item
Select
- Space / Enter - Open select
- ↓ / ↑ - Navigate options
- Type to search options
Tabs
- → / ← - Navigate between tabs
- Home / End - Jump to first/last tab
- Automatic activation on focus
Focus Management
Focus Visible
All interactive elements have visible focus indicators:
// Tailwind classes for focus states focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2
Focus Trapping
Modal components trap focus within their boundaries:
- Dialog - Focus trapped while open
- Dropdown Menu - Focus returns to trigger on close
- Tooltip - Non-interactive, doesn't steal focus
Screen Reader Support
Semantic HTML
Components use semantic HTML elements when possible:
<button> instead of <div role="button"> <nav> for navigation regions <main> for main content <aside> for complementary content <header> and <footer> for page regions
Live Regions
Dynamic content updates are announced to screen readers:
// Alert component <div role="alert" aria-live="polite"> New notification </div> // Loading states <div aria-busy="true" aria-label="Loading"> <Spinner /> </div> // Progress indication <div role="progressbar" aria-valuenow={value} aria-valuemin={0} aria-valuemax={100}>
Form Accessibility
Label Association
// Explicit label association <Label htmlFor="email">Email</Label> <Input id="email" type="email" /> // Wrapped label pattern <Label> <Checkbox /> <span>Accept terms</span> </Label>
Error Handling
<Input aria-invalid={!!error} aria-describedby={error ? "email-error" : undefined} /> {error && ( <p id="email-error" role="alert" className="text-destructive"> {error.message} </p> )}
Color Contrast
All color combinations meet WCAG AA standards:
- Normal text: 4.5:1 contrast ratio
- Large text: 3:1 contrast ratio
- Interactive elements: 3:1 contrast ratio
- Focus indicators: 3:1 contrast ratio
Testing Tools
Automated Testing
// Using jest-axe for accessibility testing import { axe } from 'jest-axe' import { render } from '@testing-library/react' test('Button is accessible', async () => { const { container } = render(<Button>Click me</Button>) const results = await axe(container) expect(results).toHaveNoViolations() })
Manual Testing
- Navigate using only keyboard
- Test with screen readers (NVDA, JAWS, VoiceOver)
- Check color contrast with browser tools
- Disable CSS to verify semantic structure
Best Practices
- Always provide text alternatives for images
- Use heading hierarchy (h1 → h2 → h3)
- Ensure interactive elements are keyboard accessible
- Provide clear focus indicators
- Use ARIA only when necessary
- Test with real assistive technologies
- Consider users with various disabilities
- Maintain consistent navigation patterns