a11y-inspector
v0.2.3
Published
Runtime accessibility auditing toolkit for modern SPAs and web apps.
Downloads
556
Maintainers
Readme
@example/dom-a11y-audit
Runtime accessibility auditing toolkit for modern single-page applications. Designed for reliability, low overhead, and privacy-first workflows.
Features
- Live DOM scanner with MutationObserver-based incremental rescans, SPA route awareness, and Shadow DOM/iframe traversal
- Production-ready rule set covering alt text, landmark/structure, focus management, keyboard traps, color contrast, forms, and cross-origin iframe reporting
- Multiple reporters: structured JSON, console groups, SARIF, and optional in-page overlay with issue markers
- Drop-in inspector button with live issue count and overlay toggle
- Strong privacy guardrails: telemetry opt-in with hashed payloads, context masking, and zero default network egress
- Extensible architecture for custom rules, formatters, and per-route configuration
- Type-safe API surface with comprehensive TypeScript declarations
- CI-friendly CLI (Node + JSDOM) with exit codes that fail builds on critical issues
Installation
npm install @example/dom-a11y-audit
# or
pnpm add @example/dom-a11y-auditQuick Start
import { initAccessibilityPlugin } from '@example/dom-a11y-audit';
const controller = initAccessibilityPlugin(document, {
overlay: true,
outputFormat: 'console',
performanceMode: 'balanced',
});
// Optional: subscribe to updates
const unsubscribe = controller.onUpdate((results) => {
console.log('a11y issues', results);
});Drop-in Inspector Button
Need a quick way to wire the overlay into your app? The library ships a ready-to-use floating button that tracks the live issue count and toggles the overlay:
import { initAccessibilityPlugin, attachInspectorButton } from 'a11y-inspector';
const controller = initAccessibilityPlugin(document, { overlay: false });
attachInspectorButton(controller, {
position: 'bottom-left',
});The button displays a real-time issue badge, triggers a fresh scan on click, and respects INSPECTOR_IGNORE_ATTRIBUTE so it never flags itself.
Configuration
| Option | Type | Default | Description |
| --- | --- | --- | --- |
| rules | string[] | all core rules | Whitelist of rule IDs to run |
| disableRules | string[] | [] | Rule IDs to disable |
| scanInterval | number | 250 | Debounce interval (ms) for incremental rescans |
| performanceMode | 'aggressive' \| 'balanced' \| 'light' | 'balanced' | Workload tuning preset |
| overlay | boolean | false | Enable in-page overlay with markers |
| outputFormat | 'json' \| 'console' \| 'html' \| 'sarif' | 'console' | Reporter to emit after scans |
| maskTextContent | boolean | false | Replace text nodes in context snippets with *** |
| telemetry | {enabled:boolean, endpoint?:string, apiKey?:string} | telemetry disabled | Opt-in remote reporting with hashed payloads |
| severityOverrides | {[ruleId]: 'critical'\|'major'\|'minor'\|'info'} | undefined | Adjust severity per rule |
| ignoreSelectors | string[] | [] | Additional selectors to skip from scans (overlay UI is ignored by default) |
| ignoreAttribute | string | 'data-a11y-inspector-ignore' | Attribute that marks DOM subtrees to ignore |
| whitelistSelectors | string[] | [] | Alias for ignoreSelectors (supported for backward compatibility) |
Overlay Preview
When enabled, the overlay renders a floating panel listing issues. Each issue receives a numbered badge positioned near the offending node. Clicking a badge scrolls to the element, keeps focus, and displays patch guidance.
To prevent the inspector controls from self-reporting, add the data-a11y-inspector-ignore attribute (or your configured ignoreAttribute) to the container that renders the plugin UI.
Framework Integrations
Call controller.createAdapters() to obtain lightweight helpers:
React: Wrap your tree with the provider:
const { createReactProvider } = controller.createAdapters();const AccessibilityProvider = createReactProvider(React);- Render
<AccessibilityProvider>{children}</AccessibilityProvider>once near the app root.
Vue 3 composition API:
const { createVuePlugin } = controller.createAdapters();app.use(createVuePlugin({ onMounted, onBeforeUnmount }));- The plugin will trigger scans on mount and cleanup on teardown.
Angular / Router Hooks: Invoke
controller.scan()inside router events (e.g.,router.events.subscribe). The DOM-driven scanner makes the integration trivial—no component instrumentation required.Plain JS: Call
initAccessibilityPlugin(document)during bootstrap. The MutationObserver keeps scans up-to-date as you mutate the DOM.
CLI Usage
# scan a static HTML export
npx @example/dom-a11y-audit cli --file dist/index.html --mask --format jsonExit status codes:
0: no issues or only informational2: at least one critical issue detected (CI-friendly)
Reporting Formats
- Console: Severity-grouped collapsible logs with color-coded suggestions.
- JSON: Structured payload matching the
ScanResultschema; perfect for snapshot tests or telemetry pipelines. - SARIF: Export machine-readable reports for GitHub Advanced Security or Azure DevOps.
- Overlay: Toggleable in-app visualization to help engineers resolve issues in context.
Rule Catalogue (Core)
| Rule | Severity | WCAG Reference |
| --- | --- | --- |
| img-alt-missing | major | SC 1.1.1 Non-text Content |
| interactive-aria-missing | critical | SC 4.1.2 Name, Role, Value |
| keyboard-tabindex-misuse | critical | SC 2.1.1 Keyboard |
| contrast-text-aa | major/critical | SC 1.4.3 Contrast (Minimum), SC 1.4.6 Contrast (Enhanced) |
| form-label-missing | major/critical | SC 1.3.1 Info & Relationships, SC 3.3.2 Labels or Instructions |
| duplicate-id | major | SC 4.1.1 Parsing |
| language-attr-missing | major | SC 3.1.1 Language of Page |
| focus-indicator-missing | major | SC 2.4.7 Focus Visible |
| iframe-cross-origin | info/major | SC 4.1.2 Name, Role, Value |
Extensibility
controller.registerRule({
id: 'custom-rule',
title: 'Example',
description: 'Checks something bespoke.',
severity: 'minor',
matcher: (root) => Array.from(root.querySelectorAll('[data-check]')),
evaluate: (element) => ({
ruleId: 'custom-rule',
selector: '',
severity: 'minor',
message: 'Element requires data-check description.',
why: 'Internal accessibility standard.',
context: '',
suggestion: {
operation: 'addAttribute',
patch: 'add data-check="description"',
example: '<div data-check="description"></div>',
},
}),
});Custom formatters can be registered via controller.getMetrics() and the exported formatter factory utilities.
Privacy & Telemetry
- Telemetry is disabled by default. No DOM or text content leaves the device unless explicitly configured.
maskTextContentredacts visible text in context outputs.- Telemetry payloads hash message strings via a deterministic, non-reversible hash before transmission.
Performance
- Incremental rescans use MutationObserver sub-tree queues and idle callbacks.
performanceModepresets balance latency versus coverage:aggressive: fastest turnaround (small debounce window)balanced: default (250 ms debounce)light: minimal CPU usage for lower-priority environments
controller.getMetrics()exposes scan timing, issue counts, and node coverage for dashboards.
Testing
- Unit: Rule matcher/evaluator behavior via Vitest and JSDOM.
- Integration: SPA route changes, MutationObserver latency, Shadow DOM fixtures, same-origin iframe traversal.
- E2E: Playwright automation sampling overlay toggles and console output.
- Snapshots: Serialize
ScanResultarrays to assert expected issues (maskTextContentfor PII).
Sample package.json scripts:
{
"scripts": {
"lint": "eslint 'src/**/*.{ts,tsx}'",
"test": "vitest run",
"test:e2e": "vitest run --config vitest.e2e.config.ts",
"a11y:scan": "a11y-scan --file dist/index.html --format sarif"
}
}CI Integration (GitHub Actions excerpt)
name: accessibility
on: [push, pull_request]
jobs:
audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v2
- run: pnpm install
- run: pnpm build
- run: pnpm test
- run: pnpm exec a11y-scan --file dist/index.html --format sarifRoadmap
- MVP: Core DOM scanner, overlay, JSON/console reporters, MutationObserver + SPA support.
- v1.0: SARIF exporter, framework adapters, telemetry scrubbing, Playwright harness, CLI packaging.
- v2.0: Visual regression annotations, IDE extensions, browser extension packaging, collaborative dashboards.
Versioning & Releases
- Semantic Versioning (SemVer) compliance (MAJOR.MINOR.PATCH).
- Maintain
CHANGELOG.mdvia Keep a Changelog format. - Before publishing: run
pnpm build && pnpm test, verifynpm pack, update changelog, tag release.
NPM Publishing Workflow
- Update
package.jsonmetadata (name, version, description, keywords). pnpm buildnpm loginnpm publish --access public
