GitHub

/ Foundations — 03

The long version of accessibility.

axe-core catches 30–40% of WCAG violations. The other 60% comes from APG keyboard tests and real screen-reader runs. Kumiki gates merges on all three.

Three layers of testing

WhatWhenCatches
axe-coreEvery PR — LTR & RTL × every documented stateStatic violations: missing labels, contrast, role validity.
APG keyboardEvery PR — Playwright per patternTab order, arrow-key nav, Home / End / Page semantics, Escape.
Guidepup screen readersNightly scheduleWhat VoiceOver and NVDA actually say, in actual order.

Required names at the type level

Where the WAI-ARIA APG mandates an accessible name (think dialogs), the requirement is enforced by TypeScript. <Dialog.Root> won't compile without one of title, aria-label, or aria-labelledby.

<Dialog.Root title="Confirm deletion">
  <!-- compiles -->
</Dialog.Root>

<Dialog.Root>
  <!-- type error: missing accessible name -->
</Dialog.Root>

Keyboard contracts

Each component documents its keymap on the component detail page (under the Accessibility tab). Where APG defines a pattern, Kumiki follows it verbatim — no creative interpretation.

Reduced motion, RTL, high contrast

  • prefers-reduced-motion shrinks all transitions to ~10 ms across the docs site.
  • RTL is not an afterthought. Direction-sensitive keymaps (Tabs, Slider) read direction from machine context, not the DOM.
  • Forced-colors mode is honoured — components avoid background-only state hints.

The "Kumiki-ready" checklist

Every component must satisfy the checklist in docs/design/05-accessibility.md §5.6 before merge. No exceptions, no --ignore flags.