Storybook addon that provides comprehensive accessibility testing for UI components using axe-core engine to ensure WCAG compliance
npx @tessl/cli install tessl/npm-storybook--addon-a11y@9.1.0Storybook Accessibility Addon provides comprehensive accessibility testing for UI components using the axe-core engine. It enables developers to automatically test their Storybook stories for WCAG compliance and web accessibility standards, offering real-time accessibility analysis with visual feedback, violation detection, color vision simulation, and detailed reporting.
npx storybook add @storybook/addon-a11yimport { PARAM_KEY, A11yTypes } from "@storybook/addon-a11y";For complete addon functionality (includes preview configuration):
import addon, {
PARAM_KEY,
A11yTypes,
A11yParameters,
run,
getTitleForAxeResult,
getFriendlySummaryForAxeResult,
getIsVitestStandaloneRun,
getIsVitestRunning
} from "@storybook/addon-a11y";For preview configuration (re-exported from main entry):
import { afterEach, initialGlobals, parameters } from "@storybook/addon-a11y/preview";For manager registration:
import "@storybook/addon-a11y/manager";For CLI postinstall (used internally by Storybook CLI):
import postinstall from "@storybook/addon-a11y/postinstall";// .storybook/main.ts
export default {
addons: ["@storybook/addon-a11y"],
};// stories/Button.stories.ts
import type { Meta, StoryObj } from '@storybook/react';
import { Button } from './Button';
const meta: Meta<typeof Button> = {
component: Button,
parameters: {
a11y: {
// Configure accessibility testing options
options: {
rules: {
'color-contrast': { enabled: true }
}
},
// Disable accessibility testing for this story
disable: false,
// Set test mode: 'off' | 'todo' | 'error'
test: 'error'
},
},
};
export default meta;
type Story = StoryObj<typeof meta>;
export const Primary: Story = {
parameters: {
a11y: {
context: {
// Include specific elements for testing
include: ['.primary-button'],
// Exclude elements from testing
exclude: ['.decorative-only']
}
}
}
};The Storybook Accessibility Addon is built around several key components:
Core configuration options for customizing accessibility testing behavior, including axe-core options, context specification, and test modes.
interface A11yParameters {
context?: ContextSpecWithoutNode;
options?: RunOptions;
config?: Spec;
disable?: boolean;
test?: 'off' | 'todo' | 'error';
}
interface A11yGlobals {
a11y?: {
manual?: boolean;
};
}Automated accessibility testing capabilities that run axe-core tests on stories through the afterEach hook, with support for different execution modes and detailed result reporting.
const afterEach: AfterEach<any> = async ({
id: storyId,
reporting,
parameters,
globals,
viewMode,
}) => Promise<void>;
interface EnhancedResults extends Omit<AxeResults, 'incomplete' | 'passes' | 'violations'> {
incomplete: EnhancedResult[];
passes: EnhancedResult[];
violations: EnhancedResult[];
}Internal React components that provide the accessibility testing interface within Storybook, automatically registered when importing the manager.
// These components are automatically registered when importing the manager
import "@storybook/addon-a11y/manager";
// Internal components (not directly importable):
// - A11YPanel: Main accessibility panel component
// - A11yContextProvider: Context provider for accessibility state
// - VisionSimulator: Vision impairment simulation toolComprehensive internal mapping system that converts axe-core rule violations into user-friendly descriptions and remediation guidance displayed in the UI.
type AxeRuleMap = {
[axeId: string]: {
title: string;
axeSummary: string;
friendlySummary: string;
};
};
const combinedRulesMap: AxeRuleMap;interface A11yTypes {
parameters: A11yParameters;
globals: A11yGlobals;
}
type A11YReport = EnhancedResults | { error: Error };
const RuleType = {
VIOLATION: 'violations',
PASS: 'passes',
INCOMPLETION: 'incomplete',
} as const;
type RuleType = (typeof RuleType)[keyof typeof RuleType];interface EnhancedNodeResult extends NodeResult {
linkPath: string;
}
interface EnhancedResult extends Omit<Result, 'nodes'> {
nodes: EnhancedNodeResult[];
}type SelectorWithoutNode = Omit<Selector, 'Node'> | Omit<SelectorList, 'NodeList'>;
type ContextObjectWithoutNode =
| {
include: SelectorWithoutNode;
exclude?: SelectorWithoutNode;
}
| {
exclude: SelectorWithoutNode;
include?: SelectorWithoutNode;
};
type ContextSpecWithoutNode = SelectorWithoutNode | ContextObjectWithoutNode;// Test runner function for executing accessibility tests
function run(input?: A11yParameters, storyId: string): Promise<EnhancedResults>;
// Rule mapping helpers for user-friendly descriptions
function getTitleForAxeResult(axeResult: EnhancedResult): string;
function getFriendlySummaryForAxeResult(axeResult: EnhancedResult): string | undefined;
// Environment detection utilities
function getIsVitestStandaloneRun(): boolean;
function getIsVitestRunning(): boolean;// Exported constant
const PARAM_KEY = 'a11y';
// Internal constants (not exported):
// const ADDON_ID = 'storybook/a11y';
// const PANEL_ID = 'storybook/a11y/panel';
// const DOCUMENTATION_LINK = 'writing-tests/accessibility-testing';
// const TEST_PROVIDER_ID = 'storybook/addon-a11y/test-provider';// CLI postinstall automation function
function postinstall(options: PostinstallOptions): Promise<void>;
interface PostinstallOptions {
yes?: boolean;
packageManager?: string;
configDir?: string;
}