a11y · git:20260707.abd2d2b · 2026-07-07 · sha256 758ba1d4c43dd8b4

a11y git:20260707.abd2d2bA

Immutable. This exact content is served forever at /api/v1/blob/758ba1d4c43dd8b4.

---
name: a11y
description: |
  Frontend accessibility audit (WCAG): semantic HTML, keyboard access, focus management,
  contrast, ARIA, screen reader. Makes the interface usable for everyone; catches regressions.
  Trigger phrases: "a11y", "accessibility", "WCAG", "screen reader", "keyboard navigation", "contrast", "ARIA"
---

# Accessibility (a11y)

Goal: make the interface usable by **everyone**, including keyboard, screen reader, and low vision. Baseline target: **WCAG 2.1 AA**.
Stack-agnostic (web/React/RN); do a web search when needed for framework-specific APIs.

## Checklist
- [ ] **Semantic HTML**: `button`/`a`/`nav`/`main`/`h1..h6` correct; no `div`-buttons
- [ ] **Keyboard**: every interaction reachable via Tab, sensible order, visible **focus ring**
- [ ] **Focus management**: focus moves on modal/route change, focus trap correct
- [ ] **Contrast**: text ≥ 4.5:1, large text ≥ 3:1
- [ ] **Alt text**: `alt` on meaningful images; `alt=""` on decorative images
- [ ] **Forms**: every input has a `label`; error message programmatically linked (`aria-describedby`)
- [ ] **ARIA**: only when needed; wrong ARIA is worse than no ARIA; role/name/state correct
- [ ] **Motion/animation**: respect `prefers-reduced-motion`
- [ ] **Language**: `<html lang>` correct (coordinate with i18n)

## How
1. **Start with semantics** — the right element solves 80%. Use `button` instead of `role="button"`+`div`.
2. **Navigate with the keyboard** — drop the mouse, run the whole flow with Tab/Shift-Tab/Enter/Escape; is focus visible and its order sensible.
3. **Naming** — does every interactive element have an accessible name (`aria-label` on visual-only icon buttons).
4. **Contrast** — check color pairs against the ratio; don't convey meaning by color alone (add an icon/text).
5. **Dynamic content** — notify the screen reader via a live region (`aria-live`); manage modal focus.
6. **Automated + manual** — tools like linters/axe are the baseline; but manual keyboard+reader testing is essential (tools don't catch 100%).

## React / RN note
- Web React: semantic element in JSX + `htmlFor`/`aria-*`; use `button` instead of a clickable `div`.
- React Native: `accessible`, `accessibilityLabel`, `accessibilityRole`, `accessibilityState` (coordinate with `frontend-rn-expo`).

## Invariant rules
1. **Semantics first, ARIA second** — wrong ARIA does harm.
2. Must be **fully usable by keyboard** — without a mouse.
3. **Color cannot be the sole carrier of meaning.**
4. **Automated tools are not enough** — manual keyboard+reader testing.
5. **Follow the existing design system** — if there is a component library, keep its accessible pattern.