a11y-audit
Skill0 starsChanged 31 days agoMITView on GitHub
Runs a real accessibility audit on a web page or local app and fixes the findings in source. Injects axe-core (WCAG 2.0/2.1/2.2 A+AA) with Playwright, then does what axe cannot: a keyboard pass that Tabs through the page to record focus order and traps, measure visible focus by pixel diff, and catch focus removed by scripts, focus hidden under sticky bars (2.4.11), clickable divs keyboard users cannot reach, hover-only menus, selects that navigate on change, and modals that ignore Escape. Produces report.md (prioritized, stack-aware fixes, grep hints), report.json, and an annotated screenshot. Includes a contrast checker that suggests the nearest passing color. Use when the user asks to "audit my app for accessibility", "check a11y", "is this WCAG AA compliant?", "fix contrast issues", "make this keyboard accessible", "check focus states", "run axe", "screen reader friendly?", or after generating or redesigning UI that should be accessible.
35 other projects use a version of this.
Adopted by
Most recently taken up by
- plugin87/ux-ui-agent-skillstheir own version, first seen Nov 10, 2026
- arcasilesgroup/ai-engineeringtheir own version, first seen Nov 8, 2026
- darkweb19/skillstheir own version, first seen Nov 8, 2026
- Aboudjem/ui-ux-suitetheir own version, first seen Nov 8, 2026
- kgelster/ecom-a11y-audittheir own version, first seen Nov 1, 2026
- jbouder/skillstheir own version, first seen Nov 1, 2026
Used with
Projects with it also use perf-audit, design-tokens and 10 more.
Other files people use alongside this one.
Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
WhatIfWeDigDeeperSkillperf-audit
Profile and optimize React application performance
Also in 4 projects that use this
ilikescienceSkilldesign-tokens
Expert in design tokens using the DTCG specification. Use this skill when users ask about design tokens, DTCG format, token validation, formatting, transformation, color spaces (sRGB, Display P3, OKLCH), references and aliasing, resolvers, theming with modifiers/contexts, multi-platform design systems, accessibility, or working with tools like jq, jsonata, and terrazzo. Helps with token file creation, resolver configuration, structure, naming conventions, and best practices.
Also in 4 projects that use this
Sagargupta16Skilldependency-audit
Audit project dependencies for security vulnerabilities, licensing issues, maintenance health, and optimization opportunities. Use it during regular security audits (monthly or quarterly); before a major release when you want to ensure the dependency tree is clean; when evaluating whether to adopt or replace a dependency; after a security advisory affects one of your dependencies; when your install times or bundle sizes have grown noticeably.
Also in 3 projects that use this
lbednerSkilli18n
Use when a code or template change introduces a new translation message key, in either the framework CLI (aegis/i18n/locales/) or a generated project's CLI (the app/i18n/locales/ template tree). Covers adding the real English string, stubbing the same key into every other locale for parity, and the separate translation PR that later replaces placeholders with reviewed native text.
Also in 3 projects that use this
GitHubSkillrefactor
Surgical code refactoring to improve maintainability without changing behavior. Covers extracting functions, renaming variables, breaking down god functions, improving type safety, eliminating code smells, and applying design patterns. Less drastic than repo-rebuilder; use for gradual improvements.
Also in 5 projects that use this
VercelSkilldeploy
Deploy applications to Vercel. Use when the user says "deploy", "deploy to Vercel", "push to production", "deploy my app", or "go live".
Also in 4 projects that use this
Other versions35 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 35
- gitkraken/vscode-gitlens★ 10ksame name
- plugin87/ux-ui-agent-skills★ 3.2ksame name
- SwitchbackTech/compass★ 227same name
- arcasilesgroup/ai-engineering★ 65same name
- helderberto/agent-skills★ 19same name
- Hassaan146/claude-skills★ 18same name
- renfei-design/Figma-AI-Bridge★ 16same name
- kgelster/ecom-a11y-audit★ 12same name
- Mozurok/fhorja.dev★ 10same name
- Aboudjem/ui-ux-suite★ 8same name
25 more not listed
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository5 other files it gives its agents.
- demo-recorderSkill
- motion-videoSkill
- pr-visual-diffSkill
- responsive-qaSkill
- token-driftSkill
The file
We split this skill into the rules it gives an agent
8 rules. 0 are common, 4 are distinctive, and 4 are very specific to this project.
0
Common
Most of the 28 edited versions we read keep these.
4
Distinctive
This author's own choices. Worth a look.
4
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 39
If Chromium download is blocked, the audit falls back to installed Chrome or Edge.
- Very specific: line 45
Not running? Start it in the background yourself (e.g.
- Very specific: line 80
Start from the report's find in source: rg -n -F "…" hint (an id, aria-label, placeholder, href, distinctive class, or the element's first …
- Very specific: line 93
No ARIA is better than bad ARIA: Add ARIA only when no native element fits, and then keep its state in sync (aria-expanded={open}).
- Very specific: line 95
Focus: never just delete outline.
- Distinctive: line 96
Keep visual design intact.
- Distinctive: line 97
Do not invent alt text you cannot infer.
- Distinctive: line 140
No check for meaning (good alt text, link text, reading order, clear errors), images of text, or media captions.
“Common” is measured: kept by at least 6 in 10 of the 28 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
A11y Audit
Measure first, fix in source, re-measure. Never declare a page accessible from reading code alone.
Scripts live in ${CLAUDE_SKILL_DIR}/scripts/ (below: $S). Output goes to ./.knack/a11y-audit/ in the user's project.
1. Setup (once)
bash "$S/setup.sh" # installs playwright 1.63.0 + axe-core 4.13.0 next to the scripts, plus ChromiumIf Chromium download is blocked, the audit falls back to installed Chrome or Edge.
2. Get a URL
- User gave a URL or an
.htmlfile path: use it. - Otherwise find the dev server: check
package.jsonscripts (dev,start,preview), the framework default port (Vite 5173, Next 3000, Astro 4321, SvelteKit 5173, Angular 4200, CRA 3000), and whether something already listens:lsof -iTCP -sTCP:LISTEN -nP | grep node. - Not running? Start it in the background yourself (e.g.
npm run dev), wait for the port, then audit. Static build output (dist/index.html) also works directly. - Pick the 1–5 pages that matter (home, a form, a list/detail, auth). Use
--pagesfor the rest.
3. Run the audit
node "$S/audit.mjs" http://localhost:5173 --pages /pricing,/loginUseful flags (full list: --help):
| Flag | Use |
--state "#menu-btn" | Also audit after clicking something (menu, modal, accordion). Repeatable. |
--mobile | Phone viewport + touch (catches target-size, hidden mobile menus). |
--viewport 320x800 | Approximates 400% zoom reflow. |
--fail-on serious | Exit 2 if any critical/serious remain (CI, or your own loop). |
--exclude "#intercom" | Skip third-party widgets you cannot change. |
--tags wcag2a,wcag2aa | Narrow the rule set (default adds WCAG 2.1/2.2 AA + best-practice). |
--json | report.json to stdout. |
--verbose | Phase timings on stderr (when a page seems slow or stuck). |
For a modal, --state "<button that opens it>" also checks that Escape closes it, focus returns to that button, and Tab does not wander onto the page behind it.
The run prints a one-line summary per page and the paths of report.md, report.json, and <page>.annotated.png (long pages also get readable <page>.annotated.partN.png slices).
4. Read the evidence (required)
- Read
report.md. It opens with Fix first (highest impact, most elements per fix) and any Coverage warnings (iframes skipped, Tab cycle cut short, page JS errors): mention those in the hand-off. Rules follow critical → minor; identical markup is grouped ("and 12 more with identical markup" = one shared component), each with the HTML snippet, why it failed, the fix, a stack-specific note when the framework was detected, and arghint. - Look at the annotated screenshot with the Read tool (the
.partN.pngslices on long pages; the full image is too tall to read). Solid boxes = axe findings, dashed = keyboard pass, blue numbered badges = focus order, magenta = no visible focus (or focus removed by script), gray = not measured (iframe). Check that the numbers follow the visual reading order. - The keyboard table lists every focus stop with its visible-focus verdict (
yes (via …)says where the indicator was found),removed by script,covered by <selector>for 2.4.11, andbehind open modal <selector>when Tab leaves an open modal.
5. Map each finding to source
Reports show the rendered DOM, so find the component that renders it:
- Start from the report's
find in source: rg -n -F "…"hint (an id, aria-label, placeholder, href, distinctive class, or the element's first text). Otherwise search for the most specific thing in the snippet.rg -n "Start free trial|btn-ghost" src/. - React/Next/JSX:
classNamenotclass,htmlFornotfor; the element is often inside a shared component (Button,Card,Input). Fix the shared component once, not every call site. Check UI kits (shadcn/ui, Radix, MUI, Headless UI) for the prop that does it (e.g.DialogTitle,aria-labelpassthrough). - Vue/Nuxt:
.vuesingle-file components;:for,@click. Svelte/SvelteKit:on:click/onclickon a<div>is the usual kbd-unreachable culprit (Svelte's own a11y warnings point at it too). - Tailwind: colors come from classes (
text-gray-400) or theme tokens (--muted-foreground,tailwind.config/@theme). Fix the token when many elements share it.outline-none/focus:outline-nonewithout afocus-visible:ring-*replacement causes kbd-focus-not-visible. - CSS-in-JS / global CSS: grep for
outline: none,outline: 0,:focus {.
6. Fix, in priority order
Work critical → serious → moderate. For each rule, open references/fix-recipes.md#<rule-id> (before/after for HTML, JSX, Tailwind) when the one-line fix is not enough.
Principles:
- Semantic HTML first.
<button>for actions,<a href>for navigation,<label for>for fields,<header>/<nav>/<main>/<footer>landmarks,<dialog>for modals, real heading levels. These fix role, name, keyboard, and focus at once. - No ARIA is better than bad ARIA. Add ARIA only when no native element fits, and then keep its state in sync (
aria-expanded={open}). Never putrole="button"on a div you could make a button. - Contrast: run
node "$S/contrast.mjs" "<fg>" "<bg>"(the report prints the exact command per failing node). It returns the nearest passing color that keeps the hue (grays stay gray), with its OKLab distance ΔE (≈0.02 is just noticeable). Ratios are truncated, never rounded up. Prefer changing the design token. Use--largefor ≥24px (or ≥18.66px bold) text and--target 3for focus rings, borders, and icons (WCAG 1.4.11). - Focus: never just delete
outline; give:focus-visiblea 2–3px ring with 3:1 contrast. - Keep visual design intact. If a fix needs a visible change (darker text, visible label), make the smallest change that passes and mention it.
- Do not invent alt text you cannot infer. Write the best alt you can from context and list it for the human to confirm.
7. Re-run until clean
node "$S/audit.mjs" <same args> --fail-on seriousLoop steps 4–7 until zero critical and serious issues (exit code 0). Re-read the annotated screenshot after the final run to confirm the focus order and that every badge is blue. Moderate/minor: fix the cheap ones; list the rest.
Heuristic checks can misfire. If you believe a finding is a false positive (e.g. a focus indicator the pixel diff missed), verify by looking at it, say why in the hand-off, and do not hack around the detector (never add a fake focus style or a dummy tabindex just to silence a rule).
8. Report back
Tell the user, briefly:
- Before → after: counts by impact from the first and last runs, and the pages/states covered.
- What changed: files touched and the kind of fix (e.g. "4 div buttons →
<button>inNav.tsx", "muted text token #a3a8b5 → #727683"). - Needs human judgment: alt text you wrote (confirm meaning), reading order, captions/transcripts, copy changes, anything excluded, and axe "needs review" items.
- Honesty line: automated checks find only part of the barriers (GDS's 142-barrier test: best tool 40%, axe 29%; Deque counts 57% by issue volume). A clean run is not "WCAG compliant". Give them the short manual checklist from
references/manual-checks.md: screen reader smoke test (VoiceOver: Cmd+F5 / NVDA), keyboard walk-through including Shift+Tab, zoom to 200% and 400% (reflow), reduced motion, captions. Say which of these you could not do yourself. Never suggest an accessibility overlay widget as a fix.
What the tools check
- axe-core 4.13 (injected, CSP bypassed, lazy iframes loaded first): ~90 rules for names, labels, contrast, ARIA validity, landmarks, headings, lang, viewport zoom, target size.
- Keyboard pass (real Tab presses, up to
--max-tabs):- focus order, traps (a cycle that never reaches the rest of the page; open modals are reported as intended; Tab stepping through a
<video controls>or date field's built-in controls is not a trap), positive tabindex, backwards visual jumps; - visible focus: screenshot before vs after focus, pixel diff on the element, then a changed ancestor (card rings via
:has/:focus-within), the<label>of a visually hidden native input, then any change within 160px (sibling indicators); fixed/sticky layers are hidden while measuring; kbd-focus-removed: focus arrives and a script blurs it (F55); the pass continues instead of stopping there;kbd-focus-obscured(2.4.11): the focused element is entirely covered by an opaque fixed/sticky layer;kbd-focus-outside-modal: that layer is an open modal or its backdrop, so focus has left the modal for the page behind it (fix:showModal()orinert, not scroll padding);kbd-unreachable: cursor:pointer, onclick, interactive role, or a real click listener (DevTools protocol) on something Tab never reaches; focus landing on invisible elements;kbd-hover-only: hidden link groups that hovering reveals but focusing (or Enter/ArrowDown on a disclosure button) does not;kbd-change-on-input(3.2.2): picks another option in each<select>; navigations, submits and popups are blocked and reported;- with
--stateon a modal: Escape closes it (kbd-dialog-escape) and focus returns to the trigger (kbd-dialog-focus-return).
- focus order, traps (a cycle that never reaches the rest of the page; open modals are reported as intended; Tab stepping through a
- Extra: inputs labelled only by a placeholder (axe accepts these; WCAG 3.3.2 wants a visible label).
- Stack detection (Next, React, Vue/Nuxt, Svelte, Angular, Astro, Tailwind, MUI, Radix) from the rendered page, used for fix notes.
Limits
- One browser engine (Chromium). Safari/VoiceOver quirks need a manual check.
- Tab goes forwards only: focus hidden by a sticky header while Shift+Tabbing up is not tested.
- Focus inside iframes is followed but not measured for visibility; cross-origin iframe content is only partly covered; closed shadow roots not at all.
- Click-handler detection is heuristic: delegated handlers with no pointer cursor are missed. Hover-menu and change-on-input checks cover hidden link groups and
<select>only. - No check for meaning (good alt text, link text, reading order, clear errors), images of text, or media captions. That is the human part.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

