Builds a per-component WCAG 2.2 accessibility checklist from a component spec - covers focus management, color contrast, ARIA roles & states, keyboard interaction, error handling, and live-region announcements - emitting a markdown checklist or YAML test plan that pairs with screen-reader-test-author for manual verification and the violation gate for automated scans. Use during component-spec review or pre-implementation acceptance.
77
97%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
A component-level a11y checklist makes acceptance criteria explicit before implementation. Without one, "is this accessible?" becomes a vague handoff between design, eng, and QA. This skill takes the component's spec (props, states, interaction model) and emits the matching WCAG 2.2 checklist.
The checklist pairs with:
screen-reader-test-author
for manual verification.a11y-violation-gate for
automated scans.The skill maps to one of these archetypes; each has its own checklist pattern:
| Archetype | Examples |
|---|---|
| Static text / display | Heading, badge, banner, blockquote. |
| Interactive - single trigger | Button, link, icon button. |
| Interactive - form input | Text input, checkbox, radio, select, switch. |
| Interactive - multi-state | Disclosure, accordion, tabs, popover. |
| Interactive - overlay | Modal, drawer, dropdown menu, command palette. |
| Composite | Combobox, date picker, multi-select, tree. |
| Live region | Toast, alert, in-page status, error banner. |
| Layout / navigation | Header, footer, breadcrumb, pagination. |
For each archetype, the matching checklist sections are below.
wcag-color-contrast).alt=""; meaningful
images have descriptive alt.<button> / <a href> used (no <div onclick>).<button>).aria-label / aria-labelledby if no visible label).aria-pressed).aria-disabled / aria-busy).<label for="..."> OR aria-labelledby referencing a
visible label.required (native) AND a non-
color cue (text or icon).aria-invalid="true" plus
an error message linked via aria-describedby.autocomplete="email", "name", etc.).aria-expanded reflects open/closed state on the trigger.aria-controls references the controlled region's id.hidden attribute or
display: none (NOT visibility: hidden or opacity: 0
which leave the content focusable).(See wcag-focus-trap for the
6-step pattern.)
role="dialog" (modal) OR role="alertdialog" (interrupt).aria-modal="true" for modals.aria-labelledby references the dialog's title.inert (or pre-inert focusable cycle).(See aria-authoring-patterns.)
aria-expanded on the trigger.aria-controls linking trigger to the popup.aria-activedescendant (when not moving DOM focus) OR
moves DOM focus into the popup.aria-selected (listbox) or
aria-checked (tree).role="status" (polite) or role="alert"
(assertive) OR aria-live="polite" / "assertive".<header> / <main> / <nav> /
<footer> / <aside>. (One <main> per page.)aria-label (e.g. "Pagination").aria-label="Breadcrumb" and
aria-current="page" on the current page.Beyond the archetype defaults, the spec may declare:
prefers-reduced-motion.The skill produces two outputs:
Manual-verification items must be emitted as concrete keystrokes
and expected announcements - never as a bare skill name. The
artifact ships into the user's repo and has to be runnable by a
tester holding only that file. Baseline commands (per the NVDA
user guide
and Apple VoiceOver;
same set as screen-reader-test-author):
| Action | NVDA + Firefox (Windows) | VoiceOver + Safari (macOS) |
|---|---|---|
| Next heading | H | VO (Ctrl+Option) + Cmd + H |
| Next form field | F | VO + Cmd + J |
| Read next / previous item | Down / Up arrow | VO + Right / Left arrow |
| Enter focus mode on a field | Enter | (automatic) |
| Activate the focused control | Enter | VO + Space |
| Element list overlay | - | VO + U (web rotor) |
A step passes when the announcement identifies the element type, reads the visible label verbatim, and conveys state and position-in-set where applicable.
## A11y Checklist - `<ComponentName>`
**Archetype:** Interactive - overlay (modal)
### Required (must pass before merge)
- [ ] Modal has `role="dialog"` and `aria-modal="true"`.
- [ ] Modal title is `aria-labelledby`-referenced.
- [ ] On open: focus moves to first focusable inside modal.
- [ ] Tab cycles within modal; outside content is `inert`.
- [ ] Escape closes; focus returns to trigger.
- [ ] Close button has accessible name "Close" or "Dismiss".
- [ ] Focus indicator on close button at ≥3:1 contrast.
### Per-component (this design adds)
- [ ] Confirmation modal's "Delete" button has `aria-describedby`
linking to the warning text.
- [ ] On confirm: live region announces "Deleted" via
`aria-live="polite"`.
### Verification
- Automated: axe-core scan with `dialog` rule enabled.
- Manual (NVDA + Firefox, Windows): press `Enter` on the trigger -
NVDA announces "Confirm delete, dialog"; `Tab` cycles inside the
dialog and never reaches page content; `Escape` closes and focus
returns to the trigger, announced as "Delete, button".
- Manual (VoiceOver + Safari, macOS): `VO`+`Space` on the trigger,
`VO`+`Right arrow` to walk the dialog contents, `Escape` to
close - same expected announcements.
- Code review: against the checklist above.component: ConfirmModal
archetype: overlay-modal
checks:
- id: AC-MODAL-1
description: Modal has role and aria-modal
severity: blocker
method: automated
rule: axe::role-modal
- id: AC-MODAL-2
description: Focus moves to first focusable on open
severity: blocker
method: e2e-test
framework: playwright
- id: AC-MODAL-3
description: Escape closes; focus restored
severity: blocker
method: e2e-test
- id: AC-MODAL-4
description: Live region announces "Deleted" on confirm
severity: blocker
method: manual
tester_role: a11y-specialist
instructions: >-
NVDA + Firefox (Windows): Tab to "Delete", press Enter.
NVDA must speak "Deleted" from the aria-live="polite" region
without focus moving. VoiceOver + Safari (macOS): VO+Space on
"Delete"; same announcement expected.| Anti-pattern | Why it fails | Fix |
|---|---|---|
| Generic checklist for all components | Static text doesn't need keyboard checks; modal does. | Per-archetype checklist; pick once. |
| Checklist created post-implementation | A11y becomes a retrofit; bugs found late. | Run this skill on the spec, before implementation. |
| Marking items "won't fix" without rationale | Loss of institutional knowledge; same item resurfaces next quarter. | Document each waiver with a date + reviewer initials. |
| One mega-checklist per component (50+ items) | Reviewer fatigue; rubber-stamping. | Per-archetype defaults; only add custom items the design demands. |
wcag-keyboard-navigation,
wcag-focus-trap,
wcag-color-contrast,
aria-authoring-patterns,
screen-reader-test-author,
a11y-violation-gate.