Accessibility
Eidetic is built with accessibility as a core principle. All components follow WCAG 2.1 AA guidelines with proper ARIA attributes, keyboard navigation, and screen reader support.
WCAG 2.1 AA
All components meet WCAG 2.1 Level AA compliance standards.
Keyboard Nav
Full keyboard navigation for all interactive components.
Screen Readers
Proper ARIA roles and labels for screen reader compatibility.
Focus Visible
Clear focus indicators on all interactive elements.
Keyboard Navigation Patterns
All Eidetic components support keyboard navigation following WAI-ARIA best practices.
GeneralBasic Navigation
DialogsModals & Dialogs
Focus is automatically trapped inside dialogs and returned to the trigger element when closed.
MenusDropdowns & Select
TabsTab Navigation
PickersDate & Time Pickers
SlidersRange Sliders
ARIA Attributes
Eidetic components use semantic ARIA roles and attributes for screen reader compatibility.
Common ARIA Patterns
Buttons with Loading State
<Button disabled aria-busy="true" aria-disabled="true"> <Spinner aria-hidden="true" /> <span>Loading...</span></Button>Form Fields with Errors
<Input aria-invalid={!!error} aria-describedby={error ? "email-error" : undefined}/><p id="email-error" role="alert">{error}</p>Modal Dialogs
<div role="dialog" aria-modal="true" aria-labelledby="dialog-title" aria-describedby="dialog-description"> <h2 id="dialog-title">Confirm Action</h2> <p id="dialog-description">Are you sure?</p></div>Listbox Selection
<div role="listbox" aria-label="Select framework"> <button role="option" aria-selected="true">React</button> <button role="option" aria-selected="false">Vue</button></div>Range Sliders
<div role="slider" aria-label="Volume" aria-valuenow={75} aria-valuemin={0} aria-valuemax={100} aria-valuetext="75%" tabIndex={0}/>Focus Management
Proper focus management ensures users can navigate efficiently.
- Focus Trap: Dialogs and modals trap focus within their boundaries to prevent users from tabbing outside
- Focus Restoration: When dialogs close, focus returns to the element that triggered them
- Focus Visible: All interactive elements have visible focus indicators (2px indigo ring)
- Skip Links: Page layouts include skip-to-content links for keyboard users
- Logical Tab Order: Focus order follows visual layout and reading direction
- No Focus Loss: Dynamically added/removed elements preserve focus context
Focus Ring Styles
/* Default focus ring (Tailwind) */.focus-ring { @apply focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 focus:ring-offset-white dark:focus:ring-offset-slate-950;}
/* Visible only for keyboard navigation */.focus-visible-ring { @apply focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 focus-visible:ring-offset-2;}Color Contrast
All color combinations meet WCAG 2.1 AA contrast requirements.
Contrast Ratios
Minimum 4.5:1 contrast ratio for body text (14-16px)
Minimum 3:1 contrast ratio for large text (18px+ or 14px bold)
Minimum 3:1 for borders, icons, and interactive elements
High contrast focus rings visible against all backgrounds
Screen Reader Support
Components are tested with major screen readers for full compatibility.
- VoiceOver (macOS): Tested with Safari on macOS for Apple users
- NVDA (Windows): Tested with Firefox and Chrome on Windows
- JAWS (Windows): Enterprise screen reader compatibility verified
- TalkBack (Android): Mobile accessibility tested on Android devices
Best Practices for Content
- Use descriptive alt text for all images and icons
- Provide aria-label for icon-only buttons
- Use semantic HTML elements (button, nav, main, etc.)
- Ensure proper heading hierarchy (h1 → h2 → h3)
- Use aria-live regions for dynamic content updates
- Hide decorative elements with aria-hidden="true"
Accessibility Testing
Recommended tools and methods for testing accessibility.
Browser Extensions
- axe DevTools - Automated accessibility testing
- WAVE - Visual accessibility feedback
- Lighthouse - Performance and accessibility audits
- Accessibility Insights - Microsoft's testing tool
Automated Testing
// Using jest-axe for component testsimport { axe, toHaveNoViolations } from 'jest-axe'
expect.extend(toHaveNoViolations)
test('Button has no accessibility violations', async () => { const { container } = render(<Button>Click me</Button>) const results = await axe(container) expect(results).toHaveNoViolations()})