---
chain-id: 5
name: A11y audit
path: A / B / C
status: live
prompts: [12]
inputs: rendered HTML or component code + output/tokens.css
outputs: output/a11y-report-<date>.md (WCAG 2.1 AA findings, severity-ranked)
documented-in: Ch23 — Quality Gates
---

# Chain 5 — A11y Audit

Audits component HTML and rendered output against WCAG 2.1 AA across six criteria: color contrast, focus visibility, semantic HTML, ARIA correctness, keyboard reachability, and touch target sizing. Produces a severity-ranked report with code-level fixes for every finding.

**When to use:**
- After Chain 3 Step 1 (foundation components) — a11y issues at foundation level are cheapest to fix
- Before any component ships to production
- After any component refactor that touches interactive states or ARIA attributes
- In CI as a pre-merge gate for component changes

**Expected runtime:** 8–15 minutes per component set. Run on foundation, composite, and domain separately for clearest output.

**Prerequisites:** Rendered HTML or component source code. `output/tokens.css`.

---

## Step table

| Step | Prompt | What lands | Checkpoint |
|---|---|---|---|
| 1 | `12-a11y-audit.md` | `output/a11y-report-<YYYY-MM-DD>.md` — WCAG 2.1 AA findings | Fix all Critical findings before proceeding |
| 2 | Per finding: regenerate affected component via Prompt 03/04/05/07 with a11y annotations | Corrected component CSS + HTML | Re-run audit to confirm zero Critical findings |

---

## Step-by-step walkthrough

### Step 1 — Run the a11y audit (Prompt 12)

**What to paste:**
- `output/tokens.css`
- The component HTML to audit — either:
  - Rendered HTML from a browser (paste the DOM output, or the component file directly)
  - Component source code from `output/foundation.css` + a basic HTML scaffold

**What gets checked:**

| Criterion | WCAG SC | What passes |
|---|---|---|
| Color contrast | 1.4.3 / 1.4.11 | Text: 4.5:1 AA. Large text (18pt+ / 14pt bold): 3:1. Non-text UI: 3:1 |
| Focus visible | 2.4.7 / 2.4.11 | :focus-visible styled, ≥2px outline, ≥3:1 contrast against adjacent colors |
| Semantic HTML | 1.3.1 | button is `<button>`, link is `<a href>`, form fields have `<label>`, heading hierarchy is logical |
| ARIA correctness | 4.1.2 | role, aria-expanded, aria-controls, aria-live, aria-hidden, modal focus trap |
| Keyboard reachability | 2.1.1 | All interactive elements reachable by Tab. Arrow keys work in menus, tabs, radios. Focus trap in modals. |
| Touch target sizing | 2.5.5 / 2.5.8 | Minimum 44×44px for all interactive targets on touch surfaces |

**Severity levels:**
- **Critical** — WCAG SC violation that blocks a user from completing a task (contrast failure on body text, button not keyboard reachable, form field has no label)
- **High** — WCAG SC violation that degrades experience (missing focus indicator, ARIA role mismatch)
- **Medium** — Best practice violation (touch target 40px instead of 44px, heading skips a level)
- **Pass** — Listed explicitly so you know what's confirmed good

**What to check at the checkpoint:**
- Zero Critical findings before any component ships. This is a hard requirement — no exceptions.
- High findings: fix in the current sprint. Do not carry High findings across more than one sprint.
- Medium findings: schedule for the next sprint.

**Common failures:**
- *Contrast failure on --color-text-faint:* Faint/muted text colors often fall below 4.5:1 against light backgrounds. The fix: darken the token value in tokens.css, then re-run Chain 1 Step 2 to propagate the change. Do not patch the component — fix the token.
- *Focus ring not visible on colored backgrounds:* If `--color-focus-ring` is too close in luminance to a component's background, the ring becomes invisible. The prompt suggests a high-contrast alternative using the `outline-offset` trick.
- *Missing aria-label on icon buttons:* Governance requires `aria-label` on all icon-only buttons. Re-run the affected component prompt with: "Every icon-only button must have an aria-label attribute."

---

### Step 2 — Fix and re-audit

**For Critical and High findings — two options:**

**Option 1 — Manual fix:**
Locate the finding's file and line. Apply the code fix provided in the report. Fast for isolated issues.

**Option 2 — Component re-generation with a11y annotation:**
Re-run the generating prompt (03, 04, 05, or 07) with the a11y report appended:
> "Re-generate [component name]. Apply these a11y fixes: [paste Critical/High findings for that component]."

The prompt regenerates only the named component with the fixes applied. Append the output to the existing CSS file — do not overwrite.

**After fixing:** Re-run Prompt 12 against the corrected component. The new report should show zero Critical findings and a reduced High count.

---

## What gets checked — detail

**Color contrast:**
Computed from actual token hex values against rendered backgrounds. The prompt does not estimate — it calculates. Every text/background pair in the component is tested. Status colors are tested against their badge backgrounds (both the solid bg and the `rgba` tint).

**Focus visible:**
The `:focus-visible` selector must be styled. `:focus` alone is not acceptable — it shows on mouse click, which is visually distracting and fails the WCAG 2.4.7 intent. Focus ring must have ≥2px width, ≥2px offset, and ≥3:1 contrast against the element's background.

**Semantic HTML:**
Audit checks for known anti-patterns: `<div onClick>` instead of `<button>`, `<a>` without `href`, placeholder used as label, nested interactive elements, form without submit semantics.

**ARIA correctness:**
Checks that ARIA attributes match the component's visual state: `aria-expanded="true"` when an accordion is open, `aria-hidden="true"` on decorative SVGs, `role="dialog"` on modals with `aria-labelledby` pointing to the dialog title.

**Keyboard reachability:**
Focus order matches visual order (Tab sequence). Composite components have correct keyboard patterns: Arrow keys navigate within tab lists and radio groups; Esc closes popovers, drawers, and modals; Home/End jump to first/last item in listboxes.

**Touch target sizing:**
Every interactive element must have a minimum 44×44px hit area. CSS `min-height`/`min-width` with padding is the correct fix — do not fake it with invisible overlays.

---

*Chain 5 · A11y Audit · Design Systems That Build Themselves · © 2026 Ishdeep S Sahni*
