Skip to content

← Back to Web A11y and Composition Review

SKILL.md

v1.0.0 · 2227 B · text/markdown

---
name: web-a11y-review
description: Use when building or reviewing web UI components - an accessibility and composition-pattern checklist covering semantics, focus, forms, motion, and component API design
---

# Web A11y & Composition Review

Two related concerns that are cheap to get right while writing a component
and expensive to retrofit afterward.

## Accessibility checklist

- **Semantic HTML first.** Reach for `<button>`, `<nav>`, `<label>` before
  a `<div>` with an `onClick` and ARIA bolted on.
- **Every interactive element is keyboard-operable** — tab order makes
  sense, focus is visible, Escape closes overlays, Enter/Space activate
  custom controls built on non-native elements.
- **Forms**: every input has a real associated `<label>`, error messages
  are programmatically associated with their field (not just colored red),
  required fields are marked in a way a screen reader announces.
- **Motion respects `prefers-reduced-motion`** — animations should degrade
  to an instant state change, not just play anyway.
- **Images and icons**: meaningful images get real alt text; decorative
  ones get empty alt text (`alt=""`), not omitted alt attributes.
- **Color is never the only signal** — pair it with an icon, label, or
  pattern for anything that conveys state (error, success, selected).

## Composition patterns

- **Compound components over boolean-prop bloat.** A component accumulating
  `variant`, `size`, `isX`, `hasY`, `showZ` props is usually better
  expressed as composable sub-components sharing context (e.g.
  `<Card><Card.Header/><Card.Body/></Card>` instead of a dozen booleans).
- **Lift state to decouple, not to centralize for its own sake.** State
  belongs at the lowest common ancestor of the components that need it —
  no higher.
- **Explicit variant components beat prop combinations** when the
  combinations aren't actually independent (a `<PrimaryButton>` and
  `<DestructiveButton>` can be clearer than `variant="primary"` vs.
  `variant="destructive"` if their internals diverge meaningfully).

## When to run this

During component review, before merging new interactive UI — not as a
one-time audit disconnected from the code that's actually shipping.