Accessibility Review for UI Code
A Claude skill that reviews pages and components against WCAG 2.2 AA: keyboard, labels, contrast, focus, forms and motion, with exact fixes.
Use it with Claude or any AI tool. Copy the prompt and paste it in. The link inside gives the AI the whole page as Markdown.
Install
mkdir -p ~/.claude/skills/accessibility-review-for-ui-code && curl -fsSL "https://ownlyplans.com/bhaskar/accessibility-review-for-ui-code/skill/?download=1" -o ~/.claude/skills/accessibility-review-for-ui-code/SKILL.md
Saves SKILL.md to your Claude skills folder. Restart Claude Code to load it.
SKILL.md
Open the fileAccessibility Review (WCAG 2.2 AA)
Review UI code so people using a keyboard, a screen reader, zoom or voice control can use it. Be concrete: point at the line, say who is blocked, and give the fix. Do not lecture.
1. Gather the facts
- Which files render the UI in question? Read the markup, the styles and the event handlers together.
- Is there a running page you can open? If Playwright is available, you may load it and run axe-core (
@axe-core/playwright, or
axe-playwright-python for Python) for a first pass. Automated tools find only part of the problems, so always do the manual checks below too.
- What are the brand colors and the smallest text size? Contrast depends on them.
2. Check, in this order
Mark each finding BLOCKER (someone cannot finish the task), SERIOUS or MINOR.
Keyboard (2.1.1, 2.1.2, 2.4.3, 2.4.7, 2.4.11)
- Everything clickable is reachable and usable with Tab, Enter and Space. A
divorspanwithonClickis a BLOCKER: usebuttonora href. - No keyboard trap. Modals move focus inside on open, keep it inside, close on Escape, and return focus to the trigger.
- Tab order follows the visual order. Flag any positive
tabindex. - Focus is always visible (never
outline: nonewithout a replacement) and not hidden under sticky headers or banners.
Names, roles and labels (1.1.1, 1.3.1, 2.4.6, 3.3.2, 4.1.2)
- Every input has a real
label(oraria-labelledby). A placeholder is not a label. - Icon-only buttons have an accessible name (
aria-labelor visually hidden text). - Images: meaningful ones have useful
alt; decorative ones havealt="". - Custom widgets (tabs, menus, comboboxes, switches) use the right role and state (
aria-selected,aria-expanded,aria-checked)
and follow the ARIA Authoring Practices keyboard pattern. Prefer native elements; no ARIA is better than wrong ARIA.
- One
h1, headings in order, and landmarks (header,nav,main,footer). The page has alangand a uniquetitle.
Seeing it (1.4.3, 1.4.4, 1.4.10, 1.4.11, 1.4.12, 1.4.1)
- Text contrast at least 4.5:1, large text (24px, or 18.66px bold) at least 3:1. Borders of inputs, focus rings and icons at least 3:1.
Compute the ratio from the real colors; check dark mode too.
- Color is never the only signal (errors, required fields, links inside text, chart series).
- Works at 200% zoom and at 320 CSS px wide without horizontal scrolling or clipped text. No fixed heights on text boxes.
Forms and messages (3.3.1, 3.3.3, 3.3.7, 3.3.8, 4.1.3)
- Errors say what is wrong and how to fix it, in text, linked to the field (
aria-describedby,aria-invalid). - Status messages (saved, 3 results, error) are announced with
role="status"oraria-livewithout moving focus. - Do not ask for the same information twice in one flow. Login must allow paste and password managers.
Pointer and motion (2.5.7, 2.5.8, 2.2.2, 2.3.1)
- Targets at least 24 by 24 CSS px (or enough spacing). Anything done by dragging also works with a single click or tap.
- Anything that moves, blinks or auto-plays for more than 5 seconds can be paused. Nothing flashes more than 3 times a second.
- Respect
prefers-reduced-motionfor large animations and parallax.
Media (1.2.x): videos have captions; audio-only content has a transcript.
3. Report
Verdict: PASS | PASS WITH FIXES | FAIL
Scope: src/components/Checkout.tsx, src/styles/checkout.css (keyboard and screen reader checked by reading code; axe: 2 issues)
BLOCKER Checkout.tsx:48 <div onClick={pay}>Pay now</div>
Keyboard and screen reader users cannot pay. WCAG 2.1.1, 4.1.2.
Fix: <button type="submit" onClick={pay}>Pay now</button>
SERIOUS checkout.css:12 .hint { color: #9aa0a6 } on #ffffff = 2.6:1
Fix: use #5f6368 (6.1:1).
MINOR ...
Then offer to apply the fixes. When you change code, keep the visual design the same unless the fix needs it (for example contrast).
4. Rules
- Cite the WCAG 2.2 success criterion number for each finding, and only ones you are sure of.
- Never claim something "passes WCAG" from automated results alone. Say what you checked and how.
- Do not add ARIA to native elements that already have the right semantics.
- If everything is fine, say PASS in one line and list what you checked.
About
Most accessibility bugs are small and easy to fix once someone points at them: a div used as a button, a field with only a placeholder, grey text that is too light, a modal that traps the keyboard. This skill makes Claude review your UI code against WCAG 2.2 level AA the way an accessibility tester would. It reads the markup, styles and handlers together, optionally runs axe-core through Playwright for a first pass, then checks keyboard use, names and labels, contrast and zoom, forms and status messages, pointer targets and motion. You get a verdict and findings marked BLOCKER, SERIOUS or MINOR, each with the file and line, the WCAG criterion, who is blocked, and the exact fix.
How to use it: save SKILL.md as .claude/skills/accessibility-review/SKILL.md in your project (or ~/.claude/skills/ for all projects). Claude picks it up when you build or change UI, or you can say “check this page for accessibility”.