If you are building React interfaces, accessibility usually starts as a small checklist item and turns into a toolchain decision. The shorthand a11y is not a package you install. It is the habit of adding checks at the points where UI bugs are easiest to catch: static linting, rendered DOM tests, and component review tools.
That is the useful frame for a short setup guide. You do not need one giant accessibility framework. You need a few focused tools that catch different classes of problems before they ship.
Start with the right mental model
Accessibility tooling works best when you treat it like layers in a pipeline.
1 Static JSX linting
Use it to catch missing labels, invalid ARIA usage, and bad semantic patterns before a component runs.
2 Rendered DOM checks
Use it to inspect the markup a component actually produces after React renders it.
3 Story-level review
Use it when designers and developers need to inspect isolated components in a predictable environment.
4 Human verification
Keep keyboard and screen reader testing in the loop for flows that real users depend on.
Install the linting layer first
For React projects, the usual first install is eslint-plugin-jsx-a11y. It adds JSX-specific rules that catch a lot of avoidable mistakes before the app even runs.
npm install -D eslint-plugin-jsx-a11y
If you are using ESLint flat config, you can start from the plugin's recommended config and then add a few project-specific rules:
import jsxA11y from 'eslint-plugin-jsx-a11y';
export default [
jsxA11y.flatConfigs.recommended,
{
files: ['**/*.{js,mjs,cjs,jsx,ts,tsx}'],
rules: {
'jsx-a11y/no-autofocus': 'warn',
'jsx-a11y/interactive-supports-focus': 'error',
'jsx-a11y/label-has-associated-control': 'error',
},
},
];
That gives you a fast feedback loop for missing labels, invalid roles, and interactive elements that are not actually keyboard friendly.
Add rendered DOM checks next
Linting is necessary, but it does not see the final rendered output. For that layer, jest-axe is a common choice because it runs the axe accessibility engine against the DOM your component actually produced.
npm install -D jest-axe @testing-library/react @testing-library/jest-dom
Then write a focused component test:
import { render } from '@testing-library/react';
import { axe, toHaveNoViolations } from 'jest-axe';
expect.extend(toHaveNoViolations);
it('keeps the dialog accessible', async () => {
const { container } = render(
<button type="button" aria-label="Save changes">
Save
</button>
);
const results = await axe(container);
expect(results).toHaveNoViolations();
});
That pattern is useful because it checks the rendered markup, not just the source code. It will not guarantee that the UI is truly accessible, but it will catch many structural errors quickly.
Add Storybook checks for component review
Storybook is a good place to review accessibility because it isolates components from the rest of the application. The accessibility addon uses axe-core to scan a story while you are looking at it.
npx storybook add @storybook/addon-a11y
If you manage the config manually, the addon entry is straightforward:
const config = {
addons: ['@storybook/addon-a11y'],
};
export default config;
That is especially helpful for design systems, where many people need to inspect the same button, dialog, or form field in a controlled environment.
Compare the layers
| Tool | Install step | Best for | Main limit |
|---|---|---|---|
| eslint-plugin-jsx-a11y | npm install -D eslint-plugin-jsx-a11y | Catching semantic mistakes in JSX before code runs | It only sees static code |
| jest-axe | npm install -D jest-axe @testing-library/react @testing-library/jest-dom | Checking the rendered DOM in unit or component tests | It cannot replace real assistive-tech testing |
| @storybook/addon-a11y | npx storybook add @storybook/addon-a11y | Reviewing isolated components during development | It depends on how well your stories mirror reality |
| Keyboard and screen reader testing | No install command | Verifying the actual user experience | It still takes human time and judgment |
Practical rules that keep the stack useful
The biggest mistake teams make is assuming a single tool is enough. A lint rule can tell you that an image needs alt text. A DOM test can tell you that a dialog opens with the right structure. Neither one can tell you whether the whole interaction makes sense when someone is using a screen reader and keyboard only.
Bottom line
Accessibility is not a separate project you start after the UI is done. It is a set of checks you install into the workflow you already have.
Start with eslint-plugin-jsx-a11y, add jest-axe for rendered component tests, and wire in @storybook/addon-a11y where your team reviews UI. Then keep the human review step in the loop, because the final accessibility test is still a real person using the interface.