accessibility-wcag-scan
Paste into Claude Code, Claude.ai, the desktop app, or the browser extension — ⌘/Ctrl+V. ✓ Copied. Switch to Claude and paste — ⌘/Ctrl+V.
Accessibility WCAG 2.2 AA Scan
Perform a comprehensive WCAG 2.2 AA accessibility audit on the specified URL, page, or component. The scan combines automated engine results with AI-judged criteria that no automated tool can evaluate reliably, then produces a structured finding report.
Usage
/accessibility-wcag-scan <URL or path> [--platform sitecore|optimizely|umbraco|headless] [--scope page|component|flow] [--target 2.0|2.1|2.2] [--level A|AA|AAA]
Examples:
/accessibility-wcag-scan https://localhost:3000/products— full-page scan (defaults to WCAG 2.2 AA)/accessibility-wcag-scan src/components/Navigation.tsx --scope component— component-level review/accessibility-wcag-scan https://localhost:3000/checkout --platform umbraco --scope flow— multi-step flow/accessibility-wcag-scan https://localhost:3000/ --target 2.1 --level AA— scan against an older target/accessibility-wcag-scan https://localhost:3000/ --level AAA— include AAA criteria in the report
Phase 0 — Determine Target Version and Conformance Level
Do this first. Every scan must state, up front, exactly which WCAG version and conformance level it is measuring against — and every finding must carry the criterion id + its level. (This is the gap Tyler flagged: "no way to determine A / 2.1 / AA / AAA, etc.")
Resolve the target. Read
--targetand--levelif supplied. If not supplied, default to WCAG 2.2 Level AA (the RBA baseline, matching ADA / EAA / Section 508 expectations).- Valid versions:
2.0,2.1,2.2. Valid levels:A,AA,AAA. - State the resolved target explicitly in the report header, e.g. "Target: WCAG 2.2 Level AA".
- Valid versions:
Build the in-scope criteria set from the canonical data file. The success criteria — each with its
version(2.0/2.1/2.2),level(A/AA/AAA), andstatus(current/new/removed) — live indata/standards/wcag.json(repo root). Read it and select the criteria that apply to the target using these rules:- Level is cumulative. A target of
AAincludes everyAandAAcriterion. A target ofAAAincludesA+AA+AAA. A target ofAincludes onlyA. - Version is a ceiling. A target of
2.1includes criteria whoseversionis2.0or2.1; a2.2target includes2.0+2.1+2.2. Never test a page against a criterion newer than the chosen target version. - Skip
status: "removed". SC 4.1.1 (Parsing) was removed in WCAG 2.2 — exclude it for a 2.2 target; include it only when the target version is explicitly 2.0 or 2.1.
Selection logic (conceptual):
levelRank = { A: 1, AA: 2, AAA: 3 } versionRank = { "2.0": 1, "2.1": 2, "2.2": 3 } inScope(c) = levelRank[c.level] <= levelRank[targetLevel] && versionRank[c.version] <= versionRank[targetVersion] && !(c.status === "removed" && versionRank[targetVersion] >= versionRank of removal)To pull the set programmatically:
cat data/standards/wcag.json# Example: list every criterion in scope for WCAG 2.2 AA node -e " const {items}=require('./data/standards/wcag.json'); const L={A:1,AA:2,AAA:3}, V={'2.0':1,'2.1':2,'2.2':3}; const tL='AA', tV='2.2'; const scope=items.filter(c=>L[c.level]<=L[tL] && V[c.version]<=V[tV] && c.status!=='removed'); console.log('In-scope criteria:', scope.length); console.table(scope.map(c=>({id:c.id,level:c.level,version:c.version,name:c.name}))); "- Level is cumulative. A target of
Carry the level + version onto every finding. For each finding you raise, look up its criterion in
wcag.jsonand record both the criterionid(e.g.1.4.3), itslevel(A/AA/AAA), and theversionthat introduced it (2.0/2.1/2.2). The level/version is never guessed — it is read from the canonical file so it stays correct as the standard evolves.Flag out-of-target observations separately. If you spot an issue against a criterion above the target (e.g. an AAA gap during an AA scan, or a 2.2 issue during a 2.1 scan), do not count it as a conformance failure. Report it under an "Beyond target (informational)" subsection, tagged with its real level + version, so the client sees it without it skewing the conformance result.
The canonical, machine-readable criteria list (id, name, version, level, short description, ref URL) is
data/standards/wcag.json.reference.mdholds a human-readable summary that mirrors it. Do not hand-maintain a second criteria list inside this skill.
Phase 1 — Environment Check
Before running the scan, verify what tools are available:
npx @axe-core/cli --version 2>/dev/null && echo "axe-cli available"
npx playwright --version 2>/dev/null && echo "playwright available"
If neither is available, proceed with static analysis only (Phases 3–5) and note the limitation.
Phase 2 — Automated Scan (axe-core)
Run the axe engine against the target. Choose the axe tag set to match the version+level resolved in Phase 0 — don't test against criteria outside the target. axe tags map to WCAG version+level as follows:
| Target | axe tags to pass |
|---|---|
| 2.0 A | wcag2a |
| 2.0 AA | wcag2a,wcag2aa |
| 2.1 AA | wcag2a,wcag2aa,wcag21a,wcag21aa |
| 2.2 AA (default) | wcag2a,wcag2aa,wcag21a,wcag21aa,wcag22aa |
| add AAA | append wcag2aaa (note: axe AAA coverage is partial — most AAA criteria stay AI-judged) |
Example for the default WCAG 2.2 AA target:
npx @axe-core/cli <URL> \
--tags wcag2a,wcag2aa,wcag21a,wcag21aa,wcag22aa \
--reporter json \
--save axe-results.json
If Playwright is available (preferred for JS-heavy SPAs and CMS edit modes):
node -e "
const { chromium } = require('playwright');
const AxeBuilder = require('@axe-core/playwright').default;
(async () => {
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto(process.argv[2]);
await page.waitForLoadState('networkidle');
const results = await new AxeBuilder({ page })
.withTags(['wcag2a','wcag2aa','wcag21a','wcag21aa','wcag22aa']) // adjust to the Phase 0 target
.analyze();
const fs = require('fs');
fs.writeFileSync('axe-results.json', JSON.stringify(results, null, 2));
await browser.close();
})();
" "<URL>"
Parse axe-results.json and extract: violations (with impact level), passes, incomplete (needs-review).
Phase 3 — AI-Judged Criteria
Automated tools reliably catch ~30–40% of WCAG issues. Evaluate the following manually by reading the page source/component code:
3.1 Alt Text Quality (SC 1.1.1)
- Images with
alt=""— is emptiness intentional (decorative) or a gap? - Functional images (linked, button): does alt describe the action, not just the image?
- Complex images (charts, infographics): is there a long description or
aria-describedby? - CMS-managed images: are alt fields required in the content model or optional?
3.2 Reading Order (SC 1.3.2)
- Does the DOM order match the visual reading sequence?
- Are CSS
order,position:absolute, or Grid placement creating a mismatch? - For carousels/tabs: does focus move logically when panels change?
3.3 Focus Sequence (SC 2.4.3 + 2.4.11 WCAG 2.2)
- Does focus move in a meaningful order through interactive elements?
- Are any focused elements fully obscured by sticky headers, chat widgets, or cookie banners? (SC 2.4.11 — new in WCAG 2.2)
- Are focus indicators visible? Check CSS
outline: none/outline: 0overrides.
3.4 Form Instructions and Labels (SC 1.3.1, 3.3.1, 3.3.2)
- Every input has a programmatically associated label (
<label for>oraria-labelledby). - Required fields are indicated both visually and programmatically.
- Error messages are associated with their field via
aria-describedby. - Inline validation doesn't remove the user's entered value.
3.5 Accessible Authentication (SC 3.3.8 — new in WCAG 2.2 AA)
- Login, registration, or 2FA flows do NOT require cognitive function tests (solving puzzles, transcribing distorted text, memorising arbitrary codes) unless an alternative method is provided.
- CAPTCHA: is there an audio or other non-cognitive alternative?
- Magic links, SSO, biometrics, or copy-paste from password manager are all compliant paths.
3.6 Target Size (SC 2.5.8 — new in WCAG 2.2 AA)
- Touch/click targets that are smaller than 24×24 CSS pixels must have adequate spacing so the surrounding offset area reaches 24×24 px.
- Icon-only buttons, close buttons, and inline links in dense lists are highest risk.
3.7 Redundant Entry (SC 3.3.7 — new in WCAG 2.2 A)
- Multi-step forms: data entered in an earlier step is auto-populated or selectable in later steps.
- Checkout flows (address → review → confirm) should not re-ask for the same data.
3.8 Consistent Help (SC 3.2.6 — new in WCAG 2.2 A)
- If a help mechanism (chat widget, phone number, FAQ link) appears on multiple pages, it appears in the same location relative to the page structure on every page.
Phase 4 — Platform-Specific Checks
Sitecore XM Cloud / SXA
- Experience Editor drag-and-drop UI: are editing controls keyboard-accessible outside edit mode?
- JSS component rendering: SSR/hydration gap — do components have valid ARIA before JS loads?
- Sitecore Forms: every field label, error, and hint must be server-rendered, not injected by JS.
- Navigation components: check for duplicate
<nav>landmarks without distinguishingaria-label.
Optimizely CMS (Content Cloud)
- Block editor reading order: does the rendered block sequence match the editor block order?
- Personalisation variants: each variant must independently pass WCAG — not just the default.
- Optimizely Forms: field groups need
<fieldset>+<legend>; radio/checkbox groups are highest risk.
Umbraco
- Grid / Block List editor: block components must declare their own landmark and heading structure.
- Members area login: evaluate against SC 3.3.8 (Accessible Authentication) — no CAPTCHAs without alt.
- Rich Text editor output: heading hierarchy, list markup, link text quality.
Headless / Composable (Next.js, Astro, React)
- Client-side navigation: focus must return to a logical target (page
<h1>or skip link) on route change. - React hydration: avoid
aria-hiddenon server HTML that gets removed after hydration. - Astro islands: ensure each island manages its own focus trap on modals/drawers.
Phase 5 — Severity Rating and Conformance Mapping
Map every finding (automated + AI-judged) using this schema. Every row must carry the criterion
SC id, its Level (A/AA/AAA), and the WCAG Version (2.0/2.1/2.2) — all three read from
data/standards/wcag.json, never guessed:
| ID | SC | Level | Version | Description | Severity | Conformance | Effort | Notes |
The Level and Version columns are what let the reader (and a VPAT) see at a glance whether a
finding is an A vs AA vs AAA gap, and which WCAG release it traces to. They are looked up from the
canonical file so they stay correct as the standard evolves.
Severity scale:
critical— blocks access for users with disabilities; legal exposure; must fix before releaseserious— significantly degrades the experience; fix in current sprintmoderate— creates friction; fix in next sprintminor— best-practice gap; fix in backlog
Conformance ratings (VPAT vocabulary):
Supports— fully meets the criterionPartially Supports— meets with exceptions (document them)Does Not Support— criterion is not metNot Applicable— criterion does not apply to this product/page
Phase 6 — Report Output
Produce a Markdown report following the structure in templates.md. Include:
- Target statement — state the resolved WCAG version + conformance level (e.g. "Target: WCAG 2.2 Level AA") at the very top, plus the count of in-scope criteria from Phase 0.
- Executive summary — overall conformance level, critical/serious count, scope.
- Conformance table — one row per in-scope criterion, each showing SC id, name, level, version, conformance rating, finding count.
- Detailed findings — grouped by guideline, each with: SC id, level, version, severity, element/location, description, remediation pointer.
- WCAG version-specific new criteria status — for a 2.2 target, explicit pass/fail for the 2.2 additions (2.4.11, 2.5.7, 2.5.8, 3.2.6, 3.3.7, 3.3.8); for a 2.1 target, the 2.1 additions.
- Beyond target (informational) — any criterion above the target (higher level or newer version) you observed, tagged with its real level + version, not counted as conformance failures.
- Platform-specific notes — only if a platform was specified.
- Next steps — link to
/accessibility-remediation-planfor backlog generation,/accessibility-vpat-acrfor formal reporting.
Reference files
data/standards/wcag.json(repo root) — CANONICAL, machine-readable. Every success criterion with itsid,name,version(2.0/2.1/2.2),level(A/AA/AAA),status, short description, and ref URL. This is the single source of truth the skill reads to determine target scope and to tag each finding's level + version. Edit the standard here, not inline.reference.md— human-readable summary that mirrorswcag.jsonplus the WCAG 2.2 quick-test checklist and how-to-use prose. Pointer to the canonical file; not a second source of truth.templates.md— Report template, finding record schema, conformance table skeleton.examples.md— Real-world finding examples per criterion with before/after code.
Technical details
- Plugin
- accessibility-auditor
- Author
- Dakota Smith
- Skill name
accessibility-wcag-scan- Maturity
- experimental
- Security review
- No security review
- Owners
-
- design
- engineering
- security
- Argument hint
<URL or component path> [--platform sitecore|optimizely|umbraco|headless] [--scope page|component|flow] [--target 2.0|2.1|2.2] [--level A|AA|AAA]- Allowed tools
-
ReadWebFetch(domain:localhost)WebFetch(domain:*.localhost)Bash(npx axe *)Bash(npx playwright *)Bash(npx @axe-core/cli *)Bash(node *)Bash(cat *)Bash(ls *)WriteEdit
- Source
plugins/accessibility-auditor/skills/accessibility-wcag-scan/SKILL.md
Edit this skill on GitHub — opens GitHub's web editor. No git knowledge needed.