GUIDELINE
Accessibility
WCAG AA guidelines built into every component. Color contrast, keyboard navigation, screen reader support, and touch targets.
Color Contrast
All text/background pairings meet WCAG AA minimum of 4.5:1:
| Pairing | Preview | Ratio |
|---|---|---|
| White / Primary text | Aa | 15.3:1 |
| White / Secondary text | Aa | 7.7:1 |
| Gray / Primary text | Aa | 14.8:1 |
| Primary / White | Aa | 5.2:1 |
| Gold / Dark text | Aa | 5.8:1 |
| Error / White | Aa | 4.5:1 |
Keyboard Navigation
- Focus rings: All interactive elements show
ring-2 ring-primary/40 ring-offset-2on:focus-visible - Tab order: Matches visual order (no custom tabIndex needed)
- ESC to close: Modals and dropdowns close on Escape
- Skip links: Add a skip-to-content link on navigation-heavy pages
// Focus ring is built into all components:
<button className="focus-visible:ring-2 focus-visible:ring-primary/40 focus-visible:ring-offset-2">
Action
</button>Form Accessibility
- Every
Inputhas an associated<label>withhtmlFor - Error messages use
role="alert"for screen reader announcement - Inputs link to hints/errors via
aria-describedby - Invalid inputs set
aria-invalid="true"
// Built into the Input component:
<label htmlFor="email">E-mail</label>
<input
id="email"
aria-invalid={!!error}
aria-describedby={error ? "email-error" : "email-hint"}
/>
{error && <p id="email-error" role="alert">{error}</p>}Touch Targets (Mobile)
- Minimum 44x44dp on all interactive elements (enforced via
TOUCH_TARGET_MIN) - Hit slop: Small dismiss buttons use
hitSlop=8 - Press feedback: All touchable elements use
Pressablewith opacity 0.7
Screen Readers
accessibilityRoleon all interactive RN components ("button", "checkbox", "radio")accessibilityStatefor disabled, checked, selected, busy statesaccessibilityLabelon icon-only buttonsaria-sorton sortable table headers (web)aria-modalon dialog overlays (web)
Reduced Motion
The global CSS includes a prefers-reduced-motion media query that disables all animations and transitions for users who prefer reduced motion.
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
transition-duration: 0.01ms !important;
}
}On React Native, check AccessibilityInfo.isReduceMotionEnabled() before running layout animations.
Checklist
- Color contrast: 4.5:1 minimum for all text
- Focus rings visible on all interactive elements
- Every form input has a
<label> - Error messages announced via
role="alert" - Tab order matches visual order
- 44dp minimum touch targets on mobile
prefers-reduced-motionrespected- No emojis as icons — SVG only