a11y-shiftleft-cli
v0.9.1
Published
Visual accessibility audit CLI for web apps using axe, Playwright, Lighthouse, and WCAG metadata.
Downloads
1,142
Maintainers
Readme
a11y-shiftleft-cli
Catch accessibility issues while you code, not after release.
a11y-shiftleft-cli is a local-first, shift-left accessibility audit tool for
frontend developers who are not accessibility specialists. Run one command
against a local, staging, or preview URL. It opens your app in a browser,
safely explores UI states, deduplicates overlapping WCAG-oriented findings, and
generates a visual HTML report with screenshots, keyboard evidence, grouped
issues, and practical fix guidance.
Use it locally during development or add it to CI/CD so pull requests get repeatable accessibility feedback before issues reach production.
It works with any rendered web app or website, including React, Vue, Angular, Next.js, Svelte, Astro, Rails, Django, and static HTML. Optional source-code adapters add framework-aware checks for React, Vue, and Angular. For SPAs and dynamic pages, the browser audit checks the rendered UI after client-side data loads, not just the initial HTML source.
Why It Helps
- Replaces several separate review steps with one developer-friendly workflow.
- Turns raw rule output into grouped, prioritized findings.
- Helps developers understand what to fix without becoming accessibility specialists first.
- Lets teams start report-only, then tighten CI gates after they understand the findings.
Built On Known Tools
The CLI orchestrates established engines instead of replacing their rule systems:
| Engine | Used for |
|---|---|
| @axe-core/playwright | Automated accessibility rules against the rendered page |
| Playwright | Browser automation, safe UI-state exploration, screenshots, and keyboard evidence |
| ESLint adapters | Optional source checks for React, Vue, and Angular projects |
| Lighthouse | Optional accessibility score comparison when installed |
The report combines these signals with deduplication, WCAG labels, visual evidence, compact WCAG review coverage, and manual-review guidance. It is an evidence workflow, not a replacement for the underlying tools or a conformance certification.
2-Minute Quick Start
Use this when your app already runs locally. You need Node.js 18 or newer, but you do not need to configure a framework first.
Privacy first: the CLI runs in your project environment and does not upload source code, screenshots, URLs, cookies, auth state, or report data to an external analysis server. Reports stay local by default.
Screenshots mask common sensitive fields such as passwords, emails, phone
numbers, payment inputs, and elements marked with data-a11y-sensitive. Use
--no-screenshots for private, authenticated, or production customer pages.
- Install the CLI and the Chromium browser used by Playwright:
npm install --save-dev a11y-shiftleft-cli
npx playwright install chromium- Start your app in another terminal:
npm run dev- Run your first visual audit. Replace
YOUR_PORTwith the port printed by your dev server:
export APP_URL=http://localhost:YOUR_PORT
npx a11y-shiftleft-cli audit --url $APP_URL --out reports --open- If the report does not open automatically:
open reports/a11y-report.htmlOn Linux use xdg-open reports/a11y-report.html. On Windows PowerShell use
start reports/a11y-report.html.
Expected result: reports/a11y-report.html opens with summary metrics,
screenshots, grouped findings, WCAG labels, and fix guidance.
Authenticated Pages
If your app requires login, create a local Playwright auth state first. The CLI opens a real browser; you log in manually, including 2FA if needed, and then the session is saved locally.
Enter your username, password, and 2FA code in the browser window opened by the command, not in the terminal. The CLI does not ask for or store your password.
Authenticated scans are still local-first: login cookies, storage state, screenshots, URLs, and reports are not sent to an external server by the CLI.
npx a11y-shiftleft-cli auth login --url https://example.com/login
npx a11y-shiftleft-cli audit --url https://example.com/account --auth-state .a11y-auth/state.json --out reports --openThe generated .a11y-auth/ folder is added to .gitignore by default. Do not
commit auth-state files because they may contain session cookies.
See the authenticated pages recipe for
post-login redirects, existing Playwright storageState files, keyboard checks,
CI-safe scripted test-account login, and privacy settings.
If a public site shows a CAPTCHA or "verify you are human" page, run a visual audit in manual verification mode. The CLI opens a visible browser, waits while you complete the challenge yourself, and then continues the scan:
npx a11y-shiftleft-cli audit --url $APP_URL --out reports --pause-on-human-verification --openAdd CI/CD
After the first local audit works, create npm scripts, the starter config,
report .gitignore entries, and a report-only CI workflow:
npx a11y-shiftleft-cli setup --url $APP_URL --start-command "npm run dev"Recommended pull-request setup: scan two or three important smoke-test pages,
keep the crawl bounded, and start in report-only mode:
npx a11y-shiftleft-cli setup \
--url http://localhost:YOUR_PORT http://localhost:YOUR_PORT/account http://localhost:YOUR_PORT/checkout \
--crawl-depth 1 \
--crawl-limit 10 \
--gate report-only \
--start-command "npm run dev"After the team reviews the first reports, tighten the PR workflow to
--gate new-critical-only. Keep slower full-site audits separate with
--profile split or a scheduled/manual workflow.
GitHub Actions is the default. For GitLab CI, add --ci gitlab:
npx a11y-shiftleft-cli setup --ci gitlab --url $APP_URL --start-command "npm run dev"For CircleCI, add --ci circleci:
npx a11y-shiftleft-cli setup --ci circleci --url $APP_URL --start-command "npm run dev"For Jenkins or another shell-based runner, generate a portable script:
npx a11y-shiftleft-cli setup --ci shell --url $APP_URL --start-command "npm run dev"Optional pre-commit checks can be generated with --git-hooks husky or
--git-hooks lefthook; they run static accessibility checks in the selected
gate mode against staged frontend files. If the project does not already use
that hook runner, setup prints the install command to enable it.
This creates .a11y-shiftleft.json, adds a11y:audit and a11y:check npm
scripts when package.json exists, updates .gitignore, and adds a CI workflow
that installs the project, runs npm run build --if-present, starts your app,
runs accessibility checks, and keeps reports as CI artifacts. Use
--build-command "<your command>" for custom generated-code or build steps, or
--no-build when CI should start the app without a separate build. Shell setup
creates scripts/a11y-ci.sh. GitHub workflows also post a pull request comment.
The default quality gate is report-only, so teams can adopt it before failing
builds on legacy issues.
After setup, local checks become:
npm run a11y:audit
npm run a11y:checkCopy-paste CI examples are available for GitHub Actions, GitLab CI, and CI/CD without SaaS. The GitHub Actions recipe also shows how to generate a CI-safe authenticated workflow for preview URLs behind login using test-account secrets.
For an existing pipeline, the smallest integration is one npm script:
{
"scripts": {
"test:a11y": "a11y-shiftleft-cli check --dynamic --url $APP_URL --out reports"
}
}Optional Framework Adapters
You do not need an adapter for the visual browser audit. audit and dynamic
check run against any rendered URL.
Adapters add source-code checks on top of the browser audit. Install only the adapter for the framework your project uses:
| Project | Optional adapter | What it adds |
|---|---|---|
| React / Next.js | @a11y-shiftleft/react | JSX/TSX accessibility lint rules |
| Vue | @a11y-shiftleft/vue | Vue template accessibility lint support |
| Angular | @a11y-shiftleft/angular | Angular template accessibility lint support |
npm install --save-dev @a11y-shiftleft/react
npm install --save-dev @a11y-shiftleft/vue
npm install --save-dev @a11y-shiftleft/angularIf you are not sure, skip adapters first and run the browser audit. Add an adapter later when you want static source findings in the same report.
What You Get
- A local visual HTML report you can open in your browser.
- Annotated screenshots that show where issues were found.
- WCAG A/AA labels, severity, confidence, and user-impact hints.
- Fix guidance, including contrast ratios and color suggestions.
- Cross-page hints for repeated page titles and potentially inconsistent navigation, help mechanisms, and same-purpose control names.
- Separate
needs reviewfindings when axe cannot prove a result automatically, such as text over images, gradients, video, or complex overlays. - Keyboard evidence and manual-review tasks for things automation cannot prove.
See The Visual Report
This is the main output of audit:
Audit Or Check?
Start with audit when a person needs to review the result. Use check when a
pipeline needs a fast pass/fail signal.
| Command | Use it when | Main output | Best for | Typical runtime |
|---|---|---|---|---|
| audit | You want a deeper local review with visual evidence | Visual HTML report with screenshots, explored states, keyboard evidence, manual-review checklist, JSON, and Markdown | Local debugging, design/dev review, sharing evidence with a team | Slower |
| check | You want a quick automated check against known URL(s) | JSON and Markdown reports, optional CI summary and baseline comparison | Pull requests, CI gates, npm scripts, regression checks | Faster |
| explore | You want to debug UI-state discovery itself | Visual exploration report for safe clicks, links, dialogs, and screenshots | Tuning depth, safe-mode blocks, screenshots, and state discovery | Medium |
Rule of thumb: run audit --url $APP_URL --out reports --open first. After the
main issues are understood, add check --dynamic --url $APP_URL --out reports
to CI.
Common Commands
The commands below assume APP_URL is set to your local, staging, or preview URL.
| Command type | Need | Command |
|---|---|---|
| audit | First local review | npx a11y-shiftleft-cli audit --url $APP_URL --out reports --open |
| agent | Run audit and get local next-step guidance | npx a11y-shiftleft-cli agent run --url $APP_URL --out reports --open |
| agent | Summarize an existing report | npx a11y-shiftleft-cli agent review --report reports |
| audit | Quick risk triage | npx a11y-shiftleft-cli audit --url $APP_URL --profile risk --out reports |
| audit | Broader local scan | npx a11y-shiftleft-cli audit --url $APP_URL --max-depth 3 --limit 50 --out reports |
| audit | Compare desktop, phone, and tablet layouts | npx a11y-shiftleft-cli audit --url $APP_URL --devices desktop mobile tablet --out reports/devices |
| audit | Compare Chromium, Firefox, and WebKit evidence | npx a11y-shiftleft-cli audit --url $APP_URL --browsers chromium firefox webkit --out reports/browsers |
| audit | Check one component or page area | npx a11y-shiftleft-cli audit --url $APP_URL --scope '#main' --out reports |
| check | Fast CI or PR check | npx a11y-shiftleft-cli check --dynamic --url $APP_URL --out reports |
| check | Save current known findings as a baseline | npx a11y-shiftleft-cli check --dynamic --url $APP_URL --out reports --update-baseline |
| check | Block only new critical regressions | npx a11y-shiftleft-cli check --dynamic --url $APP_URL --out reports --gate new-critical-only --verbose |
| check | Pre-commit static check for changed frontend files | npx a11y-shiftleft-cli check --static --staged --out reports |
| check | PR static check against a base branch | npx a11y-shiftleft-cli check --static --changed-since origin/main --out reports |
| explore | Debug visual state discovery | npx a11y-shiftleft-cli explore --url $APP_URL --out reports |
| setup | Create npm scripts, config, .gitignore, and CI workflow | npx a11y-shiftleft-cli setup --url $APP_URL --start-command "npm run dev" |
| generate-ci | Regenerate only CI workflow files | npx a11y-shiftleft-cli generate-ci --provider github --url $APP_URL --start-command "npm run dev" |
| pr-comment | Post an existing local report to a GitHub PR | npx a11y-shiftleft-cli pr-comment --repo owner/repo --pr 123 --report reports --include-labels |
| ticket export | Create reviewable Jira/Linear/GitHub issue drafts from a report | npx a11y-shiftleft-cli ticket export --report reports/a11y-report.json --out reports/a11y-tickets.md |
| evidence export | Export JSON, JSONL, or JSON-LD finding evidence for scripts or validation studies | npx a11y-shiftleft-cli evidence export --report reports/a11y-report.json --out reports/a11y-evidence.jsonl --format jsonl |
| evidence pack | Copy report artifacts into a local checksummed handoff package | npx a11y-shiftleft-cli evidence pack --reports reports --out a11y-evidence |
| evidence verify | Recheck package checksums, privacy notes, review hints, and journey summary before sharing | npx a11y-shiftleft-cli evidence verify --package a11y-evidence |
| ignore audit | Review expired or invalid temporary exceptions | npx a11y-shiftleft-cli ignore audit |
| ignore cleanup-plan | Generate a read-only cleanup plan for stale exceptions | npx a11y-shiftleft-cli ignore cleanup-plan |
| doctor | Diagnose setup problems | npx a11y-shiftleft-cli doctor --url $APP_URL |
Use --update-baseline only after reviewing the first report. The baseline is
for known existing findings, not a pass certificate. Use --gate
new-critical-only while the team fixes legacy issues without allowing new
critical regressions.
By default, audit explores up to 2 interaction levels from the start page.
--max-depth lets you change that safety limit; it does not mean "scan forever"
or "visit every possible page."
The audit automatically explores safe links, buttons, dialogs, forms, theme states, and same-origin UI transitions within bounded depth and state limits. It is designed to find issues earlier, not to certify that every page and every WCAG criterion has been fully tested.
Use 1 for a quick smoke test, the default 2 for most local reviews, and 3
or more only when you intentionally want a broader scan.
Use --scope <selector> when you want browser checks and safe UI-state
exploration to stay inside one component, dialog, checkout step, or page
section.
Use --wait-ms <ms>, --wait-for-selector <selector>,
--wait-until-url <pattern>, or --wait-until-path <path> when a SPA loads
data, redirects after login, or renders authenticated content after the first
paint:
npx a11y-shiftleft-cli audit --url $APP_URL --wait-for-selector "[data-page-ready]" --out reports
npx a11y-shiftleft-cli audit --url $APP_URL --wait-until-path /dashboard --out reportsUse --hide-elements <selectors> when cookie banners, sticky ads, chat widgets,
or other non-product overlays make screenshots noisy. Hidden selectors are
recorded in the visual and Markdown reports.
Use --browser chromium|firefox|webkit when you need evidence from another
browser engine. Use --mobile for one default phone audit, --tablet for one
default tablet audit, or --device "<Playwright device>" when you need an exact
Playwright preset. Use --devices desktop mobile tablet when you want separate
reports for several responsive profiles in one command; each profile is written
to its own subfolder under --out, with a local summary at
<out>/a11y-device-audit.html, plus Markdown and JSON summaries. These compare
finding counts, explored states, rule differences, and the highest-priority
page/state to review in each profile. The summary also calls out
profile-specific rule signals and includes coverage-overlap counts,
profile-specific page/state signals, copy-paste commands, direct links to
matching visual evidence, screenshot hints, screenshot review notes, and a short
side-by-side comparison queue with an overlay slider and screenshot-size diff
metadata for captured screenshots. When matching screenshots are PNG files with
the same dimensions, the matrix summary also records a lightweight pixel-change
percentage and shows it as a compact visual meter.
Each visual comparison item is also labeled with a review priority so the
highest-risk browser or responsive differences are easier to inspect first.
Install the browser engine before using it, for example:
npx playwright install webkitUse --browsers chromium firefox webkit when you want separate reports for
several browser engines in one command. This writes one report per browser plus
local HTML, Markdown, and JSON summaries under --out, including a difference
review for browser-specific rule signals and the first page/state to inspect in
each browser report. The summary also calls out browser-only rule signals and
coverage-overlap counts, browser-only page/state signals, copy-paste commands,
direct links to matching visual evidence, screenshot hints, screenshot review
notes, and a short side-by-side comparison queue with an overlay slider for
captured screenshots plus screenshot-size diff metadata. When matching
screenshots are PNG files with the same dimensions, the matrix summary also
records a lightweight pixel-change percentage and shows it as a compact visual
meter. Each visual comparison item is also labeled with a review priority so
the highest-risk browser differences are easier to inspect first.
Audit profiles are shortcuts:
risk: faster triage with lower depth and fewer explored states.validation: the standard local evidence profile.full: broader scan with keyboard activation checks and Lighthouse comparison. Installlighthousefirst when you want this comparison:
npm install --save-dev lighthouseExplicit flags override profile defaults, for example:
npx a11y-shiftleft-cli audit --url $APP_URL --profile risk --max-depth 2 --out reportsAfter the report opens:
- Start with the "Fix First" and screenshot sections.
- Check the manual-review tasks for keyboard, screen reader, content, and forms.
- Re-run the same command after fixing issues.
Reports and screenshots usually should not be committed. Run init --gitignore
once to add common report paths. For private pages, add --no-screenshots.
More recipes for privacy and local artifacts, user impact review, external validation, quality gates in existing projects, browser profiles, hidden overlays, and advanced configuration are in Configuration and Recipes.
Standards
Use --standard when the report needs a specific evidence context:
npx a11y-shiftleft-cli audit --url $APP_URL --standard wcag22-aa --out reports
npx a11y-shiftleft-cli audit --url $APP_URL --standard section508 --out reports
npx a11y-shiftleft-cli audit --url $APP_URL --standard ada-title-ii --out reports
npx a11y-shiftleft-cli audit --url $APP_URL --standard en301549 --out reportsAvailable presets: wcag22-aa, section508, ada-title-ii, and en301549.
They adjust labels, evidence guidance, and report context; they do not certify
legal compliance. See the Section 508,
ADA Title II, and
EN 301 549 recipes for more context.
Coverage And Limits
- The report supports accessibility review; it is not a WCAG, ADA, Section 508, EN 301 549, or EAA certification.
- Use automated evidence together with manual keyboard, screen-reader, content, and task-flow review.
- Some public websites block automated scans with bot detection or CAPTCHA.
- Third-party embeds such as YouTube, Vimeo, Spotify, Google Maps, and CodePen are marked separately when ownership can be detected.
This repository includes a React/Vite demo with intentional accessibility defects.
nvm use
npm install
npm run demo -- --port 5173In another terminal:
nvm use
npm run build
export APP_URL=http://localhost:YOUR_PORT
node bin/cli.js audit --url $APP_URL --out reportsFor the demo command above, replace YOUR_PORT with 5173.
