Accessibility audit
This is a dedicated audit pass over a page or flow - distinct from building accessible components (that's web-dev-frontend). You are measuring conformance against WCAG 2.2 AA and producing a findings list, not shipping the fixes.
Automated first pass (necessary, not sufficient)
- Run axe-core (
@axe-core/cli, or @axe-core/playwright inside an E2E test) on each page/state.
- Run Lighthouse accessibility category for a second opinion and a score.
- Automated tools catch roughly a third of issues. Never stop here - keyboard, focus, and screen-reader problems mostly don't show up automatically.
Manual checklist (WCAG 2.2 AA)
- Keyboard: every interactive element is reachable and operable by keyboard; focus order is logical; focus ring is visible; no keyboard traps;
Esc closes overlays.
- Screen reader: run VoiceOver / NVDA through the flow. Every control announces a name, role, and state. Landmarks (
main, nav, header) are present.
- Structure: exactly one
<h1>; headings don't skip levels; lists are real lists; semantic landmarks over <div> soup.
- Forms: every input has a programmatic
<label> (not just a placeholder); errors are associated (aria-describedby) and announced; required state conveyed non-visually.
- Contrast: body text ≥ 4.5:1, large text ≥ 3:1, UI components/graphics ≥ 3:1. Never convey meaning by colour alone.
- Images & media: meaningful
alt, or alt="" for decorative; captions/transcripts for audio/video.
- Dynamic content: async updates announced via
aria-live; modals trap focus and return it to the trigger on close; prefers-reduced-motion respected.
- Zoom & reflow: 200% zoom loses no content/function; at 320px width there's no horizontal scroll (reflow).
- Target size (2.2): interactive targets ≥ 24×24 CSS px (or have adequate spacing).
Static review (no browser)
When reviewing a diff rather than a running page - no axe-core, no Lighthouse, no screen reader - check what the markup and styles can tell you without executing them, and say plainly that this is a static pass, not a substitute for the automated and manual passes above:
- Semantic elements and ARIA roles/attributes are present and correctly paired (a
role="button" div also gets a keyboard handler and tabindex).
- Every form control's label, in the markup, either wraps it or matches its
for/id.
- Interactive elements are real buttons/links/inputs, not a
<div onClick>.
- Colour tokens against the design system's own contrast pairs, where the values are visible in the diff.
alt text is present and isn't the filename.
Reporting findings
Rank by user impact:
- Blocker - an assistive-tech user cannot complete the task (unlabeled submit, keyboard trap, invisible focus).
- Serious - major barrier with a workaround (poor contrast on key text, missing headings).
- Moderate / Minor - friction or best-practice gaps.
For each finding give: the WCAG success criterion (e.g. 1.4.3, 2.4.7, 2.5.8), the location (page + element/selector), the user impact, and the specific fix.
What this skill is not
- Not the fix step - hand remediation to
web-dev-frontend, which owns building accessible components.
- Not a substitute for real AT testing - the manual pass with an actual screen reader is where the real findings come from.
1---2name: a11y-audit3description: Accessibility audit of a page or flow: axe-core, Lighthouse, and a WCAG 2.2 AA manual checklist, severity-ranked with fixes. Use for an a11y audit, WCAG conformance, screen reader or keyboard testing, or contrast ratios. Building accessible components belongs to web-dev-frontend.4license: MIT5---67# Accessibility audit89This is a dedicated *audit pass* over a page or flow - distinct from building accessible components (that's `web-dev-frontend`). You are measuring conformance against WCAG 2.2 AA and producing a findings list, not shipping the fixes.1011## Automated first pass (necessary, not sufficient)1213- Run **axe-core** (`@axe-core/cli`, or `@axe-core/playwright` inside an E2E test) on each page/state.14- Run **Lighthouse** accessibility category for a second opinion and a score.15- Automated tools catch roughly a third of issues. **Never stop here** - keyboard, focus, and screen-reader problems mostly don't show up automatically.1617## Manual checklist (WCAG 2.2 AA)1819- **Keyboard:** every interactive element is reachable and operable by keyboard; focus order is logical; focus ring is visible; no keyboard traps; `Esc` closes overlays.20- **Screen reader:** run VoiceOver / NVDA through the flow. Every control announces a **name, role, and state**. Landmarks (`main`, `nav`, `header`) are present.21- **Structure:** exactly one `<h1>`; headings don't skip levels; lists are real lists; semantic landmarks over `<div>` soup.22- **Forms:** every input has a programmatic `<label>` (not just a placeholder); errors are associated (`aria-describedby`) and announced; required state conveyed non-visually.23- **Contrast:** body text ≥ 4.5:1, large text ≥ 3:1, UI components/graphics ≥ 3:1. Never convey meaning by colour alone.24- **Images & media:** meaningful `alt`, or `alt=""` for decorative; captions/transcripts for audio/video.25- **Dynamic content:** async updates announced via `aria-live`; modals trap focus and return it to the trigger on close; `prefers-reduced-motion` respected.26- **Zoom & reflow:** 200% zoom loses no content/function; at 320px width there's no horizontal scroll (reflow).27- **Target size (2.2):** interactive targets ≥ 24×24 CSS px (or have adequate spacing).2829## Static review (no browser)3031When reviewing a diff rather than a running page - no axe-core, no Lighthouse, no screen reader - check what the markup and styles can tell you without executing them, and say plainly that this is a static pass, not a substitute for the automated and manual passes above:3233- Semantic elements and ARIA roles/attributes are present and correctly paired (a `role="button"` div also gets a keyboard handler and `tabindex`).34- Every form control's label, in the markup, either wraps it or matches its `for`/`id`.35- Interactive elements are real buttons/links/inputs, not a `<div onClick>`.36- Colour tokens against the design system's own contrast pairs, where the values are visible in the diff.37- `alt` text is present and isn't the filename.3839## Reporting findings4041Rank by user impact:4243- **Blocker** - an assistive-tech user cannot complete the task (unlabeled submit, keyboard trap, invisible focus).44- **Serious** - major barrier with a workaround (poor contrast on key text, missing headings).45- **Moderate / Minor** - friction or best-practice gaps.4647For each finding give: the **WCAG success criterion** (e.g. 1.4.3, 2.4.7, 2.5.8), the **location** (page + element/selector), the **user impact**, and the **specific fix**.4849## What this skill is *not*5051- Not the fix step - hand remediation to `web-dev-frontend`, which owns building accessible components.52- Not a substitute for real AT testing - the manual pass with an actual screen reader is where the real findings come from.