Accessibility standard
WCAG 2.1 AA for all UI work. Semantic HTML first, ARIA only when needed. Keyboard-navigate everything. Test with axe-core + real screen reader.
Accessibility standard
Purpose: Defines WCAG 2.1 Level AA accessibility requirements for all framework child projects. Serves as a developer quick-reference for color contrast, keyboard navigation, semantic HTML, ARIA patterns, forms, and testing.
This standard defines accessibility requirements for all framework child projects. It is a developer quick-reference — for deep audits, invoke the Accessibility Auditor agent.
Target: WCAG 2.1 Level AA conformance.
Color contrast
| Element | Minimum Ratio | Example |
|---|---|---|
| Normal text (< 18px / 14px bold) | 4.5:1 | Body copy, labels, links |
| Large text (≥ 18px / 14px bold) | 3:1 | Headings, large buttons |
| UI components & graphical objects | 3:1 | Borders, icons, focus rings |
Use the browser DevTools contrast checker or npx @axe-core/cli to validate.
All 43 framework themes must pass these ratios.
Keyboard navigation
Every interactive element must be operable with keyboard alone:
- Tab — Moves focus forward through interactive elements in logical order
- Shift+Tab — Moves focus backward
- Enter/Space — Activates buttons and links
- Escape — Closes modals, dropdowns, overlays; focus returns to trigger
- Arrow keys — Navigate within composite widgets (tabs, menus, radio groups)
- No keyboard traps — Users can always Tab away from any element
- Visible focus indicator — On every focusable element (never
outline: nonewithout a replacement)
Focus management for dynamic content
- Modals — Trap focus inside. On close, return focus to the element that opened it.
- Route changes (SPA) — Announce the new page title. Move focus to the main content area or
<h1>. - Toast/notifications — Use
aria-live="polite"so screen readers announce without stealing focus. - Delete/remove actions — Move focus to the nearest logical element after the removed item.
Semantic HTML first
Use native HTML elements before reaching for ARIA:
| Instead of | Use |
|---|---|
<div role="button" tabindex="0"> |
<button> |
<div role="link"> |
<a href="..."> |
<div role="heading" aria-level="2"> |
<h2> |
<span role="checkbox"> |
<input type="checkbox"> |
The best ARIA is the ARIA you don't need. Radix UI primitives (used by shadcn/ui) handle most ARIA patterns correctly — don't override their defaults unless you have a specific reason.
Common ARIA patterns
When native HTML isn't sufficient:
aria-label— Labels for elements without visible text (icon buttons, search inputs)aria-describedby— Associates error messages with form fieldsaria-live="polite"— Announces dynamic content changes (toasts, status updates)aria-expanded— Indicates open/closed state (accordions, dropdowns)aria-hidden="true"— Hides decorative content from screen readers- Never put on focusable elements
ARIA anti-patterns (do NOT)
- No
aria-labelon non-interactive elements — Don't apply to<div>or<span> - No role swapping — Don't add
role="button"to<a>or vice versa; use the correct element - No
aria-hidden="true"with focusable children — Hides the container but leaves children reachable - No
tabindex> 0 — Breaks natural tab order
Forms
- Labels — Every
<input>,<select>,<textarea>must have an associated<label>(viahtmlFor/idor wrapping) - Required fields — Use
aria-required="true"and visual indicator - Error messages — Associate with
aria-describedbypointing to the error element - Field grouping — Group related fields with
<fieldset>and<legend>(radio groups, address blocks) - Validation errors — React Hook Form + Zod errors should be announced
- Use
aria-liveon the error container oraria-describedbyon the input
- Use
Images and media
- Informative images — Descriptive
alttext - Decorative images —
alt=""(empty string, not missing) - Complex images — Charts, diagrams:
altsummary + longer description viaaria-describedby - Icons as buttons —
aria-labelon the button,aria-hidden="true"on the icon SVG
Testing checklist
Run before every PR that touches UI:
# Automated scan (catches ~30% of issues)
npx @axe-core/cli http://localhost:3000 --tags wcag2a,wcag2aa
Manual checks (catches the other 70%):
- Tab through the entire page — can you reach everything? Logical order?
- Activate every button/link with Enter or Space
- Open and close every modal/dropdown with keyboard
- Check focus visibility — can you always see where you are?
- Test with VoiceOver (macOS: Cmd+F5) — do headings, landmarks, and labels make sense?
- Zoom to 200% — does layout reflow without horizontal scrolling?
- Enable
prefers-reduced-motion— do animations respect it?
For comprehensive audits, invoke the Accessibility Auditor agent.
See also
standards/core/review-protocol.md— Accessibility in code review- Standards agent — Standards compliance checks including accessibility (
.claude/agents/standards.md) ui-ux-pro-maxskill — Quick accessibility rules for design work