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-vitestrenders every story in Chromium via Vitest browser mode;@storybook/addon-a11yinjects 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.tssetsparameters.a11y.test = 'error', which turns axe violations into test failures (the default,'todo', only reports). axe is scoped to AA viaoptions.runOnlytags (wcag2a … wcag22aa). - Wired by inheritance.
apps/storybookhas atestscript, soturbo run test→pnpm test→pnpm gate→ci.ymlpick 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.tsunderparameters.a11y(options,config,context), or per story via story-levelparameters.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.