MA

muhnad/a11y-checker

Developer tools
117 stars Quality 55 Trend 43

Accessibility scanner for humans and AI agents.

Overview

Framework-agnostic accessibility scanner for AI agents and CI. Scan any web app, whatever it is built with, or lint source code directly. Scan a whole project or just the files and directories you name. Findings are structured, each with a fix hint. - : renders a URL, an HTML page or an HTML string in Chromium and runs axe-core. It checks what the browser actually shows, so it works for any stack: React, Next.js, Angular, Vue, Svelte, plain HTML/JS and more. - : lints code directly. Supported today: - React and Next.js (JS/TS/JSX/TSX) with eslint-plugin-jsx-a11y - React Native with eslint-plugin-react-native-a11y, the only option for React Native - Vue single-file components (including ) with eslint-plugin-vuejs-accessibility - Astro (.astro) with the jsx-a11y rules from eslint-plugin-astro. Optional: run npx a11y-checker init to enable it - Angular templates (.html and inline template:) with @angular-eslint - A directory scan also renders any full HTML pages it finds.

README

a11y-checker

Framework-agnostic accessibility scanner for AI agents and CI. Scan any web app, whatever it is built with, or lint source code directly. Scan a whole project or just the files and directories you name. Findings are structured, each with a fix hint.

  • Web engine (any framework): renders a URL, an HTML page or an HTML string in Chromium and runs axe-core. It checks what the browser actually shows, so it works for any stack: React, Next.js, Angular, Vue, Svelte, plain HTML/JS and more.
  • Source engine (no running app needed): lints code directly. Supported today:
  • Agent ready: a CLI with --json, an MCP server, an agent skill and an AGENTS.md block. An agent scans, fixes and rescans, limited to the files or directories you name.

For frameworks without a source linter yet (Svelte, template engines such as Handlebars or EJS), scan the running app’s URL. A source scan tells you when it skipped files it has no rules for, so a clean result is never silent about what it didn’t check.

Upgrading from v2? v3 is a rewrite. See Migrating from v2.

Install

npm install --save-dev a11y-checker
npx playwright install chromium   # needed for web scans

npx a11y-checker init does the install for you: it adds a11y-checker and, for an Astro project, eslint-plugin-astro, using the project’s package manager after asking. It also offers to add the a11y instructions to AGENTS.md. It only prints what it would do when it isn’t run in a terminal, and --yes skips the questions.

Requires Node 22+. The Chromium download is only needed for the web engine (URLs, HTML files and strings, and full HTML pages found in a directory scan); a scan of source code alone doesn’t use it.

CLI

npx a11y-checker https://example.com          # a URL
npx a11y-checker ./dist/index.html            # an HTML file
npx a11y-checker src                          # a source directory (React, Next.js, React Native)
npx a11y-checker src/Button.tsx               # a single source file
npx a11y-checker src/cart src/Header.tsx      # only these directories and files
npx a11y-checker ''          # an HTML string

Pass several targets to scan only those. The target decides the engine: URLs, full HTML pages and HTML strings use web; other files and directories use source. A directory scan covers every kind it finds: JS/TS/JSX/TSX, Angular templates (.html fragments and inline template: strings) and full HTML pages (rendered and checked with axe).

Option Description
--json Print findings as a JSON array
--fail-on Exit 1 if any finding is at or above minor, moderate, serious or critical (default minor)
--tags Comma-separated axe tags, e.g. wcag2aa,wcag22aa (web only)
--wait-for Wait for this selector before scanning (web only)
--changed Scan only source files changed since HEAD plus new files. Targets, if given, limit the search. Fast for CI and for rescans after a fix

Exit codes: 0 ok, 1 findings at or above the threshold, 2 usage or runtime error. Notes about skipped files go to stderr as Warning: ..., so --json output stays parseable.

Each finding looks like this:

{
  "engine": "web",
  "ruleId": "image-alt",
  "impact": "critical",
  "wcag": ["wcag2a", "wcag111"],
  "message": "Images must have alternative text",
  "helpUrl": "https://dequeuniversity.com/rules/axe/4.14/image-alt",
  "fixHint": "Add alt=\"\" to the image, or alt=\"\" if it is purely decorative.",
  "selector": "img",
  "html": ""
}

Source findings have file and line instead of selector and html. Web findings also carry url (the page scanned) or, for a local HTML file, file, so a multi-page scan stays readable.

Frameworks

Project Scan Notes
React, Vue, Svelte, any web app URL of the running app Checks the rendered page, including contrast
Next.js src or app directory, and each route’s URL Source scan is static; the URL scan catches what only exists at runtime, such as next/image alt text
Angular the source directory, and the running app’s URL Source scan lints .html templates and inline template: strings
Plain HTML the file or directory Pages are rendered and checked with axe
Vue the source directory, and the running app’s URL Source scan lints .vue files
Astro the source directory, and the running site’s URL Source scan lints .astro files once eslint-plugin-astro is installed (see below); without it they are skipped with a warning
Svelte, DOM built in plain JS URL of the running app No static source rules yet; a source scan warns that it skipped these files
React Native the source directory Static only. There is no runtime scan of a device or simulator yet

For multi-page apps, scan each route’s URL.

Use in CI

- run: npm ci
- run: npx playwright install --with-deps chromium
- run: npx a11y-checker src --fail-on serious

Use from code

import { scan, exceedsThreshold } from 'a11y-checker';

const findings = await scan('https://example.com', { tags: ['wcag2aa'], onWarning: console.warn }); // or scan(['src/a', 'src/b.tsx'])
if (exceedsThreshold(findings, 'serious')) process.exit(1);

Use with AI agents

Three pieces work with any coding agent. Use any of them; none is tied to one vendor.

  • MCP server exposes scan_page, explain_rule and an a11y-fix prompt (the scan, fix, rescan, report workflow, with an optional target argument). Add a stdio server with the command npx -y a11y-checker mcp. Most clients take the JSON below, but the file it goes in and the top-level key (mcpServers, servers, …) differ per client, so check your client’s docs.
  • Skill, skills/a11y-fix/SKILL.md, in the open Agent Skills format, teaches the same workflow. It works on the files, directories or URLs you name (“check src/components”), not the whole codebase unless you ask.
  • AGENTS.md, the file most agents read for project instructions, tells the agent to scan after UI changes.
{
  "mcpServers": {
    "a11y-checker": { "command": "npx", "args": ["-y", "a11y-checker", "mcp"] }
  }
}
npx a11y-checker init                 # installs a11y-checker, then offers to add the a11y block to AGENTS.md
npx a11y-checker install-skill        # skill into .agents/skills and .claude/skills of this project
npx a11y-checker install-skill --global                # ... or ~/.agents/skills and ~/.claude/skills
npx a11y-checker install-skill --agent agents          # only the cross-client .agents/skills (or --agent claude)

init asks before installing or writing anything (and only prints what it would do when it isn’t run in a terminal); in AGENTS.md it appends or replaces just its own marked block. install-skill doesn’t ask: it writes the skill folders, and refuses to replace an existing install unless you pass --force. With --global it writes under your home directory.

How agents pick these up:

Agent Skill AGENTS.md
Claude Code .claude/skills (install-skill) or the plugin below Add @AGENTS.md to CLAUDE.md
Codex, Cursor and other Agent Skills clients .agents/skills (install-skill) Read natively
Gemini CLI .agents/skills Set context.fileName to ["AGENTS.md"] in .gemini/settings.json
Aider n/a, use the MCP prompt Add read: AGENTS.md to .aider.conf.yml
Any other MCP client n/a, use the a11y-fix prompt See your client’s docs

Claude Code plugin (skill and MCP server together):

/plugin marketplace add Muhnad/a11y-checker
/plugin install a11y-checker@a11y-checker

Limits

  • Automated checks find only part of the problems. Do a keyboard and screen reader pass too.
  • Source scans skip test files (*.test.*, *.spec.*, __tests__, __mocks__) and don’t run react-native-a11y/has-accessibility-hint, which flags nearly every React Native element.
  • Source findings carry no WCAG tags and are all reported as serious, because the ESLint rules don’t provide them.
  • The source engine doesn’t check Next.js `` alt text. The web engine does.
  • Angular templates are linted with @angular-eslint’s accessibility rules. They can’t see content that only exists at runtime; scan the running app too.
  • Source scanning skips file types it has no rules for (for example .svelte, .hbs, .ejs) and says so with a warning. The warning comes through the CLI’s stderr, as an extra block after the findings in the MCP result, and through onWarning in scan().
  • eslint-plugin-astro is an optional peer dependency, not installed by default: the releases that work with ESLint 9 depend on a package (braces) with an unpatched advisory, and we don’t want it in every install. Install it only if you scan Astro code: npx a11y-checker init adds it, and a11y-checker itself, to the project (it finds the right package manager from the lockfile and asks first). The plugin is looked up from the scanned directory, so a bare npx a11y-checker finds it too.
  • Rules are axe-core’s and the two ESLint plugins’; see axe rules.

Migrating from v2

v2 ran ~19 hand-written checks in the browser and logged to the console (a11yChecker()). v3 removes that API and replaces it with the engines above. Replace the call with a CLI or scan() step in CI or in your agent. The v2 code is kept on the v2 branch and the v2.2.1 tag.

Contributing

git clone [email protected]:Muhnad/a11y-checker.git
cd a11y-checker
npm install
npx playwright install chromium
npm test
Command Description
npm run build Build dist/ with tsup
npm run lint ESLint
npm run typecheck tsc --noEmit
npm test Build, then run all tests (including real Chromium and ESLint)
npm run test:unit Unit tests only, no browser

Please open an issue before a large change.

Other tools

Tool Description
axe-core The accessibility rules engine behind the web scan
eslint-plugin-jsx-a11y Static a11y rules for JSX
eslint-plugin-react-native-a11y Static a11y rules for React Native
Awesome a11y validators More testing and validation tools

License

MIT

View this README on GitHub

Recommended Tools

Try a different keyword or remove a filter.

Install

npx skillfish add muhnad/a11y-checker