InfinitiBit Design System

Axe Accessibility Gate

Automated axe checks that fail the build on WCAG 2.2 AA violations.

Axe Accessibility Gate

WCAG 2.2 AA is non-negotiable. The axe gate checks every story's structure — names, roles, color contrast — in a real browser and fails the build on any violation. It runs inside the same pnpm gate command as everything else, so it fires locally and in CI with no extra steps.

axe is automatic on every story; you don't write a11y tests, you write stories. Operability (Tab / Enter / focus) is a separate, per-component concern — see the Keyboard & focus gate.

Use it

Every story is an axe subject automatically. To run the check:

pnpm gate                                    # full suite, incl. axe
pnpm --filter @infinitibit_gmbh/storybook test    # a11y gate only

The first run downloads a headless Chromium (the test script installs it for you); subsequent runs reuse it. If a story has a violation, the run fails and axe prints the rule, the offending element, and a fix link — for example:

"Elements must meet minimum color contrast ratio thresholds (color-contrast)"
  Element has insufficient color contrast of 1.91 ... Expected contrast ratio of 4.5:1

Fix the component (or the story) until the gate is green.

How it works

  • Real browser, real DOM. @storybook/addon-vitest renders every story in Chromium via Vitest browser mode; @storybook/addon-a11y injects axe per story. A real browser is required so layout-dependent rules like color-contrast actually run — jsdom can't compute them.
  • The gate is one parameter. .storybook/preview.ts sets parameters.a11y.test = 'error', which turns axe violations into test failures (the default, 'todo', only reports). axe is scoped to AA via options.runOnly tags (wcag2a … wcag22aa).
  • Wired by inheritance. apps/storybook has a test script, so turbo run testpnpm testpnpm gateci.yml pick it up with no workflow edit — the extension model from Testing & CI.

See ADR 0010 for the full rationale (and why jsdom vitest-axe was rejected).

Maintain it

  • Add coverage by adding stories — no per-component wiring.
  • Tune axe globally in .storybook/preview.ts under parameters.a11y (options, config, context), or per story via story-level parameters.a11y.
  • Scope a check to a known issue with story-level overrides rather than weakening the global rule set; prefer fixing the component.
  • Automated ≠ full AA. axe catches a meaningful subset; pair it with the Keyboard & focus gate and broader manual review from beta.

On this page