Accessibility
WCAG 2.1 AA is the non-negotiable baseline. Every component ships with a documented contract, verified in CI.
The baseline never bends
If an interaction pattern can’t meet WCAG AA, the design changes — not the requirement. axe-core, the token contrast contract, and the jsx-a11y lint rule all fail the build on violations.
§1
What every component guarantees
Four pillars that hold for every variant, severity, and size.
Keyboard
- All functionality reachable via keyboard.
- No keyboard traps — Tab always escapes.
- Tab order is logical: DOM order matches visual order.
- Esc closes overlays — Dialog, Sheet, Popover, Dropdown, Tooltip.
- Enter and Space activate the focused control.
Focus management
- Focus ring visible on :focus-visible (keyboard), hidden on mouse.
- Ring is 2px solid, 2px offset, colour --color-border-focus.
- Focus trap inside Dialog, Sheet, and Drawer.
- Focus returns to the trigger when a modal closes.
- Skip-to-main link in the page layout, visible on focus.
ARIA
- Semantic HTML first — ARIA only where HTML falls short.
- aria-label required for icon-only interactive elements.
- aria-describedby links helper text and errors to inputs.
- aria-live regions announce form errors and toasts.
- aria-current="page" on the active nav link.
- aria-busy="true" during loading states.
Beyond colour
- State is never colour alone — pair it with an icon and ARIA.
- Alerts and toasts carry a severity icon plus role.
- Type sizes are rem-based, so they scale with browser settings.
- Motion respects prefers-reduced-motion automatically.
§2
Colour contrast
The CI token contract validates every severity × variant pair against these minimums.
| Element | Minimum contrast |
|---|---|
| Normal text | 4.5:1 |
| Large text (18pt+ regular, 14pt+ bold) | 3:1 |
| UI component borders | 3:1 against adjacent |
| Focus indicator | 3:1 against adjacent |
§3
Target size and motion
Physical reachability and respect for user preferences.
Target size
Minimum touch target is 44×44px, met by the default size="md" on interactive components.
size="sm" is allowed only where density justifies it, such as dense tables.
Reduced motion
Motion tokens collapse to near-zero under prefers-reduced-motion: reduce.
Essential feedback, like focus rings, stays fully functional.
§4
How it’s verified
Automated gates plus a manual matrix per component.
Automated
- axe-core fails the build on any violation.
- Token contract test fails on contrast violations.
- jsx-a11y ESLint rule catches common mistakes.
- Visual regression catches focus-ring changes.
Manual matrix
- Keyboard-only, no mouse.
- NVDA, VoiceOver, TalkBack, Switch Control.
- 200% zoom and high-contrast mode.
- prefers-reduced-motion and forced colours.