diff --git a/README.md b/README.md index 30a1cd5..a518651 100644 --- a/README.md +++ b/README.md @@ -1,33 +1,40 @@ # @ngbracket/a11y-devtools -Accessibility auditing for Angular that maps each axe violation back to **the -component that rendered it**, so you get `♿ UserCardComponent — 2 issue(s)`, not a -wall of CSS selectors. Run it as a dev overlay while you build, or headless in CI. +Finds accessibility problems in Angular apps and names the component behind each one. +Use it as an overlay while you develop, or headless in CI. It runs axe-core, plus its +own keyboard checks if you turn them on, and groups the results by component: + +```text +♿ UserCardComponent — 2 issue(s) + critical · image-alt: Images must have alternative text + serious · color-contrast: Elements must meet minimum color contrast ratio thresholds +``` -**📖 Documentation: [ngbracket.com/tools/a11y-devtools/docs](https://ngbracket.com/tools/a11y-devtools/docs/introduction)** -(guides, every option and CLI flag, and the rule catalogue). +Documentation: [ngbracket.com/tools/a11y-devtools/docs](https://ngbracket.com/tools/a11y-devtools/docs/introduction) +has the guides, every option and CLI flag, and the rule catalogue. You can also try the +[live demo](https://a11y-demo.ngbracket.com/a11y-demo) without installing anything. Part of the `@ngbracket` Angular tooling family. ## Features -- **Component attribution**: every finding names the Angular component to fix, - walking past UI-library components (Material, CDK, Nebular, …) to yours. Uses +- Component attribution: every finding names the Angular component to fix. It skips + past UI-library components (Material, CDK, Nebular and others) to yours, using Angular's documented dev debug API (`window.ng`). -- **In-app provider**: rescans as the app settles; grouped console output and an - optional on-page overlay. Switch it on and off with the on-page pill or - Alt+Shift+A; the pill's menu picks what's drawn (highlights, tab order, focus - preview, minimum severity) and downloads an HTML report of the routes you've - visited. Choices are remembered. -- **Report mode**: scan many routes headless from the CLI; Markdown, JSON and a - self-contained HTML report. -- **CI gating with a baseline**: fail only on *new* issues, so an app with known - issues can adopt the gate today. -- **Dark mode**: scan your dark theme too, whether it follows the OS setting, a - class, an attribute, or custom logic. -- **Keyboard & Focus Mode**: tab-order visualisation, keyboard findings, - Focus preview (computed role, name and state), and keyboard-trap detection with real Tab presses. -- **Zero production weight**: a no-op in production; axe-core is never loaded. +- In-app provider: rescans each time the app settles, logs findings grouped by + component, and can draw an overlay on the page. Turn it on and off with the + on-page pill or Alt+Shift+A. The pill's menu picks what's drawn and downloads an + HTML report of the routes you've visited. +- Report mode: scans many routes headless from the CLI and writes Markdown, JSON + and a self-contained HTML report. +- CI gating with a baseline: fails only on new issues, so an app with known issues + can add the gate straight away. +- Dark mode: scans your dark theme too, however your app switches to it. +- Keyboard & Focus Mode: numbers the tab order, adds keyboard findings, shows the + Focus preview card (computed role, name and state), and finds keyboard traps by + pressing Tab for real. +- Production weight: does nothing in production builds, and axe-core isn't loaded + there. ## Install @@ -38,7 +45,7 @@ npm i -D @ngbracket/a11y-devtools npm i -D playwright && npx playwright install chromium ``` -Needs Angular 18+. +It needs Angular 18 or later. ## Quick start @@ -56,8 +63,8 @@ export const appConfig: ApplicationConfig = { ![Keyboard & Focus Mode over the demo page: numbered tab-order badges (badge 1 in orange flags a positive tabindex) joined by a connector path, severity-coloured finding highlights labelled with their owning component (including the ngbr/* -keyboard findings), and the focus-follow accessibility-tree panel showing the -focused button's computed role, name and states.](./demo/keyboard-layer-2026-09.png) +keyboard findings), and the Focus preview card showing the focused button's +computed role, name and states.](./demo/keyboard-layer-2026-09.png) In CI (`--serve` starts `ng serve`, waits for it, and stops it after the scan): @@ -78,13 +85,13 @@ Next steps, in the docs: [CLI reference](https://ngbracket.com/tools/a11y-devtools/docs/cli) · [Findings & rules](https://ngbracket.com/tools/a11y-devtools/docs/findings) -## What it can't do +## What it leaves to you -Automated checks cover part of WCAG, so a clean run is necessary, not sufficient: -keyboard, screen-reader and human testing cover the rest. The keyboard findings are -heuristics, labelled "verify manually". It helps you build toward supporting WCAG -2.2 AA; it doesn't certify conformance. See -[What it checks (and what it can't)](https://ngbracket.com/tools/a11y-devtools/docs/coverage). +Automated checks cover part of WCAG. The rest needs manual testing: keyboard, screen +reader, zoom and review by people. The keyboard findings are heuristics, +each labelled "verify manually". The tool helps you build toward supporting WCAG 2.2 +AA; it doesn't certify conformance. See +[What it checks](https://ngbracket.com/tools/a11y-devtools/docs/coverage). ## Develop @@ -111,13 +118,13 @@ ever becomes reachable through a static import. ### Planned -- Headless "linear walkthrough" — the tab sequence as an SR-ish reading list per - route in report-mode (M2's preview is currently overlay-only). +- A headless "linear walkthrough": the tab sequence as a reading list per route in + report mode. The Focus preview is overlay-only for now. - Per-component filtering and a violation-count badge. ### Done -- Component attribution — the nearest app-owned component, walking past UI primitives. +- Component attribution: the nearest app-owned component, skipping UI primitives. - Directive and `hostDirectives` attribution. - Configurable framework prefixes. - axe scan. @@ -128,10 +135,10 @@ ever becomes reachable through a static import. - HTML report output. - Baseline/diff mode: CI fails only on new issues. - Dark-mode scanning: `--color-scheme`, `--dark-class` / `--dark-attribute`, and theme-aware hooks. -- **Keyboard & Focus Mode M1** — tab-order visualisation + keyboard-reachability findings. -- **Keyboard & Focus Mode M2** — focus-follow accessibility-tree preview. -- **Keyboard & Focus Mode M3** — missing focus-trap detection (uncontained - `aria-modal`) and the keyboard-trap walk with real Tab presses. +- Keyboard & Focus Mode M1: tab-order visualisation and keyboard-reachability findings. +- Keyboard & Focus Mode M2: the focus-follow accessibility-tree preview (now called Focus preview). +- Keyboard & Focus Mode M3: missing focus-trap detection (an `aria-modal` that doesn't + contain focus) and the keyboard-trap walk with real Tab presses. - CI production-weight guard. - Real-browser E2E tests, including component attribution in a real Angular app. - Report mode can start the dev server (`--serve`). diff --git a/demo/README.md b/demo/README.md index f91ea31..cc966bf 100644 --- a/demo/README.md +++ b/demo/README.md @@ -4,10 +4,10 @@ Three ways to see `@ngbracket/a11y-devtools` working. ## 1. Standalone overlay (no Angular app needed) -`index.html` feeds the overlay hand-made findings so you can see the *rendering* -— severity-coloured boxes, component-labelled chips, click-to-scroll — on a plain -page. The compiled `dist/overlay.js` is framework-agnostic, so no build tooling is -involved beyond `tsc`. +`index.html` feeds the overlay hand-made findings on a plain page, so you can see how +it draws them: severity-coloured boxes, chips labelled with the component, and +click-to-scroll. The compiled `dist/overlay.js` doesn't depend on Angular, so the +only build step is `tsc`. ```bash npm run build @@ -29,34 +29,33 @@ providers: [ ]; ``` -On the live `/login` page the tool runs a real axe scan, attributes every -violation to its owning component, and overlays them — nine `region`/`landmark` -findings, each labelled (`Login`, `NgbrPasswordField`, `NgbrLoginForm`, -`NgbrAuthField`, `NgbrAuthDivider`): +On the `/login` page the tool runs an axe scan, finds the component that owns each +violation, and draws them on the page. Here that's nine `region` and `landmark` +findings, labelled `Login`, `NgbrPasswordField`, `NgbrLoginForm`, `NgbrAuthField` +and `NgbrAuthDivider`: ![end-to-end in the admin console](e2e-admin-login.jpeg) -This exercises the whole pipeline together: dynamic axe scan → `window.ng` -component attribution → grouped console reporter → overlay → zoneless-aware -rescan, all behind the dev-only provider (tree-shaken out of production). +That one page uses every stage: the axe scan, component attribution through +`window.ng`, the grouped console report, the overlay, and rescanning in a zoneless +app. All of it sits behind the dev-only provider, which is tree-shaken out of +production builds. ### All four severity colours -The admin app also ships a **dev-only** `/a11y-demo` route (registered only under -`isDevMode()`, so it never reaches production) that trips one axe rule per impact -level. It's the quickest way to see the overlay's full palette — critical (red), -serious (orange), moderate (yellow), minor (blue) — and the matching grouped -console report: +The admin app also has an `/a11y-demo` route, registered only under `isDevMode()`, +that fails one axe rule at each impact level, so you can see all four overlay +colours: critical (red), serious (orange), moderate (yellow) and minor (blue). ![all four overlay severity colours](all-severities.png) -The grouped, component-attributed console report the overlay writes alongside it — -one summary line, then findings grouped by the component that rendered each: +The console report written alongside it has one summary line, then the findings +grouped by the component that rendered each one: ![grouped, component-attributed console report](grouped-console-2026-09.png) -Run it across a real app, fix what it surfaces, and the report goes quiet — here's -the admin `/login` page after clearing every violation the tool found there: +After we fixed the violations it found on the admin `/login` page, the report for +that page is empty: ![console reporting no violations after the fixes](login-no-violations-console-2026-09.png) @@ -83,11 +82,10 @@ and manual keyboard, screen-reader and content review is still required: ## Local-link caveat (integrators) -When **linking this package into an app locally** (not installing a published -version), give it a real directory under the app's `node_modules` containing only -`dist/` + `axe-core` — **not a plain symlink to the source checkout**. A symlink -drags in the package's own `@angular/core`/`rxjs`, so the app ends up with *two* -Angular instances; the `ENVIRONMENT_INITIALIZER` the provider registers then -belongs to the wrong instance and is silently ignored (no overlay, no scan). A -normal published `npm install` resolves those peers to the consumer's single copy -and avoids this entirely. +To link this package into an app locally instead of installing a published version, +create a real directory under the app's `node_modules` that contains only `dist/` and +`axe-core`. Don't symlink the source checkout. A symlink brings in the package's own +`@angular/core` and `rxjs`, so the app has two copies of Angular. The provider's +`ENVIRONMENT_INITIALIZER` then registers with the wrong copy and never runs, so you +get no overlay and no scan. A normal `npm install` of a published version uses the +app's own copy of those peers, so it doesn't have this problem. diff --git a/package.json b/package.json index 295603e..1d9549d 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@ngbracket/a11y-devtools", "version": "0.15.6", - "description": "Dev-only in-app accessibility auditing for Angular that maps each axe violation back to the component that rendered it — the attribution React overlay tools can't do.", + "description": "Finds accessibility problems in Angular apps and names the component behind each one. A dev overlay, or headless reports for CI.", "license": "MIT", "author": "Duncan Faulkner", "contributors": [