Storybook a11y addon test-runner reports violations in CI
The Storybook test-runner, wired with axe-playwright in a postVisit hook (or via the a11y addon), scanned a rendered story and found violations. The runner reports the failing story with the axe rule ids.
What this error means
The test-runner marks a story as failed with an "Accessibility" section listing violations (for example button-name, color-contrast), often from a component story that renders an isolated control.
FAIL Button/Icon Only
Accessibility
Expected the HTML found to have no violations:
button-name: Buttons must have discernible text (critical) - 1 nodeCommon causes
The component story itself has a violation
Rendering the component in isolation surfaces its own accessibility defect, such as an icon-only control with no accessible name.
A story renders without the wrappers that provide context
A control that needs a label or landmark in the app is shown bare in the story, so axe flags what the real page would provide.
How to fix it
Fix the component or the story
- Read the rule id in the story failure.
- Fix the component (add aria-label, alt, contrast) or add the missing context in the story.
- Re-run the test-runner to confirm the story passes.
// enable the a11y check in the test-runner
const { getStoryContext } = require('@storybook/test-runner');
const { injectAxe, checkA11y } = require('axe-playwright');
module.exports = {
async postVisit(page) { await injectAxe(page); await checkA11y(page); },
};Disable a rule per story with parameters
Use the story a11y parameters to disable a specific rule with a note when it is a context-only false positive.
Story.parameters = {
a11y: { config: { rules: [{ id: 'region', enabled: false }] } }, // isolated control
};How to prevent it
- Run the a11y check across stories in the test-runner.
- Provide required context (labels, landmarks) in decorators.
- Disable rules per story only with a documented reason.