GitHub

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.

ElementMinimum contrast
Normal text4.5:1
Large text (18pt+ regular, 14pt+ bold)3:1
UI component borders3:1 against adjacent
Focus indicator3: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.