Back to skills

A11y

Code

A11y

Purpose: make web content accessible. Minimum target: WCAG 2.2 Level AA.

Definitions

  • Scope: the exact pages, journeys, and states you will test.
  • Matrix row: one combination of route, state, viewport, and input mode.
  • Evidence: a recorded result that another person can reproduce.

Workflow checklist

Copy this checklist and track your progress:

Audit Progress:

  • 1. Choose the mode
  • 2. Establish the boundary
  • 3. Build the matrix
  • 4. Capture the baseline
  • 5. Triage findings
  • 6. Remediate (remediate mode only)
  • 7. Verify (remediate mode only)
  • 8. Report

1. Choose the mode

Two modes exist. Choose one before any other step.

  • Audit mode: inspect and report only. Do not change product source code.
  • Remediate mode: inspect, fix, add regression coverage, and re-verify.

Audit mode executes steps 1, 2, 3, 4, 5, and 8. Remediate mode executes steps 1 through 8.

2. Establish the boundary

Record, in writing, all of the following:

  1. Mode: audit or remediate.
  2. Target surfaces: changed feature, selected routes, or representative sample.
  3. User tasks: the essential actions users must complete.
  4. Support baseline: browsers, assistive technology, and versions.
  5. Data constraints: authentication, test accounts, and fixtures.
  6. Evidence location: where results will be stored.

If the scope is ambiguous, choose a narrower scope. A narrow scope produces a true claim. A broad scope produces a false claim.

Done when: mode, scope, support baseline, constraints, and evidence location are all explicit.

3. Build the matrix

Create one row for each combination of:

  • Route or journey.
  • UI state: empty, loading, populated, error, authenticated, dialog, menu, toast, drag.
  • Viewport: mobile, desktop, and intermediate widths.
  • Input mode: keyboard, pointer, touch, screen reader.

Give every row a stable identifier, for example checkout-empty-mobile-kb.

Output the matrix table. Stop. Do not run axe until the user confirms the rows.

Done when: the user has confirmed the rows.

4. Capture the baseline

4.1 Automated checks

  1. Detect the project's package manager, test runner, and browser test setup.

  2. Use axe-core. WCAG 2.2 rules are disabled by default in axe-core. Enable them before the run. See references/axe-setup.md for working configuration in common test stacks.

  3. Select the full WCAG 2.2 A/AA tag set. Each axe rule carries exactly one WCAG version and level tag, so select every tag up to the target:

    runOnly: {
      type: "tag",
      values: ["wcag2a", "wcag2aa", "wcag21a", "wcag21aa", "wcag22a", "wcag22aa"]
    }
    

    The tag wcag22a currently matches no rules. Include it anyway. The set stays valid and future-proof.

  4. Run automated checks against every rendered state. Axe does not test hidden content: inactive menus, closed dialogs, and unrendered regions are skipped. Activate each state, then re-run.

  5. Save the raw output per row: violations, incomplete results, tool version, browser, viewport, and state.

  6. Run the manual matrix in references/manual-audit.md for every applicable category.

Tool order, from best to last resort:

  1. Existing browser tests with an axe integration.
  2. Existing browser automation that can expose dynamic states.
  3. Project-local axe CLI or axe-core in the test stack.
  4. Static source inspection, only when the app cannot run. If you use it, report reduced confidence.

Lighthouse score is not evidence. Output axe violations per matrix row. Do not use Lighthouse as a substitute for axe or the manual matrix.

Done when: every row has automated evidence and applicable manual evidence, or a written reason why it cannot be tested.

4.2 Manual checks

Load references/manual-audit.md. For every matrix row, mark each category Applicable or N/A. Do not force irrelevant work. Complete every check in each applicable category, or record why it cannot be tested. Record the exact browser, operating system, assistive technology, and version for all screen-reader evidence.

5. Triage findings

Prioritize in this order:

  1. Blocks an essential task.
  2. Appears on shared surfaces: layout, navigation, forms.
  3. Confirmed WCAG A or AA violation.
  4. User impact.
  5. Confidence.
  6. Fix leverage versus regression risk.

For every finding, record:

  • Affected matrix rows.
  • User consequence.
  • Evidence.
  • The WCAG criterion.
  • Confidence.
  • Proposed fix.
  • Verification method.

Audit mode: continue to step 8. Do not fix code.

6. Remediate

  1. Fix root causes in small batches. Verify after each batch.
  2. Prefer native HTML, visible labels, and established project primitives.
  3. Treat every ARIA role as a contract for keyboard and focus behavior.
  4. Keep all rules enabled. If you disable a rule, record the reason and its impact on the claim.
  5. Add regression tests in the existing test stack.

Done when: every confirmed in-scope A/AA failure and critical task barrier is fixed, or explicitly deferred with a reason and evidence.

7. Verify

  1. Re-run the identical matrix.

  2. Compare before and after evidence with scripts/compare-evidence.mjs:

    node scripts/compare-evidence.mjs before.json after.json
    

    The script exits 1 if any finding was added. That is the intended behavior.

  3. Inspect every new and every incomplete result.

  4. Exercise essential journeys with keyboard and with each declared browser and assistive-technology combination.

  5. Record remaining limitations.

Done when: no unexplained mismatch remains, and manual checks and project tests pass.

8. Report

Use this exact template:

Accessibility report: <scope>

Mode and scope

  • Mode: <audit | remediate>
  • Surfaces: <target surfaces>
  • Matrix: <N rows, identifier range>

Environment

  • Browsers: <names and versions>
  • Assistive technology: <names and versions>
  • Tools: <axe-core version and other tools>

Findings

#SeverityWCAG SCLocationUser impactEvidenceStatus
1critical2.5.8path:line<consequence><evidence>fixed / deferred

Evidence

  • <per-row before/after summary>
  • Raw output: <location>

Risks and exclusions

  • <unresolved risks>
  • <deferrals with reason and evidence>

Claim limits

  • <what was tested and what was not>

Rules for claims:

  • "Axe zero" is an instrument reading, not conformance.
  • "Lighthouse 100" is an instrument reading, not conformance.
  • Claim only what you tested: surfaces, states, environments, and methods.
View on GitHub