Loading...
Loading...
Audit, implement, and fix web accessibility with a screen-reader-first lens. Use when building or reviewing UI components, forms, dialogs, navigation, dynamic content, or any interactive element. Covers WCAG 2.2 AA compliance, ARIA patterns, keyboard navigation, focus management, and assistive technology compatibility (NVDA, JAWS, VoiceOver). Trigger on: "accessible", "a11y", "screen reader", "WCAG", "ARIA", or when adding any interactive UI.
npx skill4agent add connorads/dotfiles accessibility<button><nav><h2>| Priority | Category | WCAG Level | See |
|---|---|---|---|
| 1 | Accessible names (buttons, inputs, links) | A | references/aria-patterns.md |
| 2 | Keyboard operability (all interactive elements) | A | references/focus-management.md |
| 3 | Focus management (dialogs, SPAs, live regions) | A/AA | references/focus-management.md |
| 4 | Semantic structure (headings, landmarks, lists) | A | references/wcag-checklist.md |
| 5 | Form errors and validation | A/AA | references/common-fixes.md |
| 6 | Colour contrast and visual states | AA | references/wcag-checklist.md |
| 7 | Dynamic content announcements | AA | references/aria-patterns.md |
| 8 | Images and media | A | references/wcag-checklist.md |
Need an interactive control?
↓
Does a native HTML element do this? → YES → Use it. Done.
↓ NO
Use the correct ARIA role + required attributes + keyboard handler.
Adding dynamic content?
↓
Does focus move to the new content? → YES → No live region needed.
↓ NO
Is it a transient status (toast, cart count, form error)?
→ Use aria-live="polite" (or role="alert" for errors)
Opening a dialog/modal?
→ Trap focus inside. Restore focus to trigger on close.
→ See references/focus-management.md<label>aria-labelaria-labelledbyaria-labelaria-hidden="true"outline: nonetabindex<!-- ❌ Screen reader announces: "button" -->
<button><svg>...</svg></button>
<!-- ✅ Screen reader announces: "Close, button" -->
<button aria-label="Close"><svg aria-hidden="true">...</svg></button><!-- ❌ Screen reader announces: "edit text" -->
<input type="email" placeholder="Email" />
<!-- ✅ Screen reader announces: "Email address, edit text" -->
<label for="email">Email address</label>
<input id="email" type="email" /><!-- ❌ Not keyboard accessible, no role announced -->
<div onclick="save()">Save</div>
<!-- ✅ Free keyboard support, correct role -->
<button onclick="save()">Save</button><!-- ❌ Error visible but not associated with the field -->
<input id="email" type="email" />
<span>Please enter a valid email</span>
<!-- ✅ Screen reader announces error when field is focused -->
<input id="email" type="email"
aria-describedby="email-err"
aria-invalid="true" />
<span id="email-err" role="alert">Please enter a valid email</span><!-- ❌ Cart count updates, screen reader users never know -->
<span id="cart-count">3</span>
<!-- ✅ Announces "4 items in cart" when count changes -->
<span id="cart-count" aria-live="polite" aria-atomic="true">4 items in cart</span>HDaria-labelaria-labelledbyaria-describedbyaria-live="polite"role="alert"assertivearia-hidden="true".visually-hidden:not(:focus):not(:active) {
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}aria-label| Content type | Minimum ratio |
|---|---|
| Body text (<18pt / <14pt bold) | 4.5:1 |
| Large text (≥18pt or ≥14pt bold) | 3:1 |
| UI components (borders, icons, focus rings) | 3:1 |
| Placeholder text | 4.5:1 |
| Disabled elements | Exempt |
| File | Contents |
|---|---|
| references/screen-readers.md | NVDA/JAWS/VoiceOver commands, browse vs. forms mode, testing scripts per component type |
| references/aria-patterns.md | ARIA roles, labelling hierarchy, live region patterns, complex widget ARIA (combobox, tabs, tree) |
| references/focus-management.md | Modal focus trap, SPA route change focus, skip links, focus restoration patterns |
| references/wcag-checklist.md | WCAG 2.2 AA criterion-by-criterion checklist with pass/fail examples |
| references/common-fixes.md | Code-level fix templates for the 20 most common audit findings |