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