Accessibility Standards
Code must conform to WCAG 2.2 Level AA.
Workflow: Plan accessible implementation → generate → review against WCAG 2.2 → iterate. Suggest Accessibility Insights for testing.
Language: People-first ("person using a screen reader," not "blind user"). No ability stereotypes. Flag uncertain implementations with reasoning.
Cognitive
Plain language; consistent landmarks and nav order across pages; minimal distractions.
Keyboard
- All interactive elements keyboard-navigable with visible focus in reading order.
- No
tabindexon static elements;tabindex="-1"only for elements receiving programmatic focus. - Hidden elements must not be focusable.
Composite components and detailed complex patterns have been moved to REFERENCE.md to keep this skill focused. See REFERENCE.md for roving tabindex, aria-activedescendant, and composite widget examples.
Validation checkpoints (run-fix-repeat)
- Run an automated audit:
npx axe-coreor integrateaxe-core/axe-playwrightin CI — fix high/critical findings. - Verify keyboard tab order manually:
Tabthrough the page, ensure logical order and visible focus. - Confirm contrast ratios (spot-check key pages): use
axe,pa11y, orcontrasttools and ensure ≥4.5:1 for body text. - Fix, re-run audits, and repeat until no high/critical a11y issues remain.
Skip link (first focusable element):
<a href="#maincontent" class="sr-only">Skip to main</a>
<main id="maincontent"></main>
.sr-only:not(:focus):not(:active) { clip: rect(0 0 0 0); clip-path: inset(50%); height: 1px; overflow: hidden; position: absolute; white-space: nowrap; width: 1px; }
| Key | Action |
|---|---|
Tab |
Next interactive element |
Arrow |
Navigate within composite component |
Enter |
Activate focused control |
Escape |
Close dialogs/menus |
Low Vision
| Rule | Requirement |
|---|---|
| Text contrast | ≥4.5:1 (≥3:1 for large text: 18.5px bold / 24px) |
| Graphics/controls | ≥3:1 with adjacent colors |
| State indicators (pressed, focus, checked) | ≥3:1 |
| Color | Never the sole conveyor of information |
Screen Reader
- Correct semantics (name, role, value, states). Prefer native HTML; ARIA only when necessary.
- Landmarks:
<header>,<nav>,<main>,<footer>. - One
<h1>per page;<h1>–<h6>introduce sections; no skipping levels.
Voice Access
- Interactive element accessible name must contain its visible label text.
aria-labelmust include the visible label.
Forms
- Labels accurately describe control purpose.
- Required fields: asterisk in label +
aria-required="true". - Errors:
aria-invalid="true"+aria-describedbypointing to error message. - Don't disable submit — show errors instead; focus first invalid field on submit.
Images
| Type | Pattern |
|---|---|
| Informative | alt="[meaning]" on <img>; role="img" + aria-label on <svg> / icon fonts |
| Decorative | alt="" on <img>; aria-hidden="true" on role="img" |
Input Labels
<label for="id">for form inputs; all interactive elements need visible labels.- Disambiguate repeated labels (e.g., "Remove") with
aria-label. - Help text via
aria-describedby.
Navigation
<nav><ul>
<li><button aria-expanded="false" tabindex="0">Section 1</button>
<ul hidden><li><a href="..." tabindex="-1">Link 1</a></li></ul>
</li>
</ul></nav>
- Use
<nav>+<ul>, NOTmenu/menubarroles. - Toggle
aria-expandedon expand/collapse;Escapecloses menus. - Roving tabindex across main items; arrow down into sub-menus.
Page Title
<title>describes page purpose, unique per page.- Front-load unique info:
"[Page] - [Section] - [Site]".
Tables & Grids
- Column headers:
<th>in first<tr>; row headers:<th>in each row. role="gridcell"nested withinrole="row".<table>for static data;role="grid"for interactive (date pickers, calendars).
Converted and distributed by TomeVault — claim your Tome and manage your conversions.