AugmentClaude

Accessibility Validator

Scan code for WCAG 2.1 AA and EU accessibility compliance issues.

Installation

  1. Make sure Claude is on your device and in your terminal.

    Skills load from ~/.claude/skills/ when Claude Code starts up — so you need it on your machine first. If you don't have it yet, install it once with the command below, then run claude in any terminal to verify.

    One-time setup
    npm i -g @anthropic-ai/claude-code

    Already have it? Skip ahead.

  2. Paste into Claude Code or into your terminal.

    This copies the whole skill folder into ~/.claude/skills/a11y-validate-softspark/ — the SKILL.md plus any scripts, reference docs, or templates the skill ships with. Safe default: works for every skill.

    Faster alternative (instruction-only skills)

    Skips the clone and grabs only the SKILL.md file. Don't use this if the skill ships Python scripts, reference markdowns, or asset templates — they won't be downloaded and the skill will fail when it tries to load them.

    Quick install (SKILL.md only)
    Sign up to copy
  3. Restart Claude Code.

    Quit and reopen Claude Code (or any other agent that loads from ~/.claude/skills/). New skills are picked up on startup.

  4. Just ask Claude.

    Skills auto-activate when your request matches the skill's description — no slash command needed. Trigger phrases live in the skill's own frontmatter; you can read them in the “What this skill does” section above.

Prefer to read the source first? Open on GitHub.

When Claude uses it

Accessibility validator: WCAG 2.1 AA, EN 301 549, EAA. Triggers: a11y, accessibility, WCAG, EAA, ARIA, contrast, keyboard, screen reader.

What this skill does

/a11y-validate — Accessibility & EAA Compliance Scanner

$ARGUMENTS

Scan a codebase for accessibility issues using pattern-matching heuristics. Detects violations of WCAG 2.1 Level AA, EN 301 549 (the EU harmonized accessibility standard), and the European Accessibility Act (Directive (EU) 2019/882, "EAA", in force since 28 June 2025). Read-only — never modifies files.

Complements /seo-validate (which only covers SEO-a11y overlap shallowly). Use this skill when the concern is legal accessibility compliance, not search engine ranking.

Standards basis:

  • WCAG 2.1 Level A + AA — W3C Recommendation 2018 (updated 2023).
  • WCAG 2.2 Level AA (opt-in via --standard wcag-2.2-aa) — adds 2.4.11 focus not obscured, 2.5.8 target size minimum, 3.2.6 consistent help, 3.3.7 redundant entry, 3.3.8 accessible authentication.
  • EN 301 549 v3.2.1 — EU harmonized standard; aligned with WCAG 2.1 AA plus additional chapters for mobile, hardware, ICT procurement, authoring tools, and functional-performance statements.
  • EAA / Directive (EU) 2019/882 — legal framework requiring EN 301 549 conformance for consumer-facing digital products and services in EU markets. Deadline: 28 June 2025. Requires accessibility statements per member-state templates.

Usage

/a11y-validate                                # Scan full project, auto-detect framework
/a11y-validate src/                           # Scan specific path
/a11y-validate --scope keyboard               # Only keyboard + focus checks
/a11y-validate --scope media                  # Only captions/transcripts/autoplay
/a11y-validate --scope docs                   # Only EAA accessibility-statement check
/a11y-validate --scope mobile                 # Only React Native + Flutter patterns
/a11y-validate --standard eaa                 # Activate EAA documentation category
/a11y-validate --standard wcag-2.2-aa         # Add WCAG 2.2 criteria
/a11y-validate --severity high                # Filter to HIGH findings
/a11y-validate --framework react-native       # Force framework
/a11y-validate --output json                  # Structured JSON for CI integration

Scopes:

  • full (default) — all 8 categories
  • keyboard — Category 3 only
  • contrast — Category 4 only
  • forms — Category 5 only
  • media — Category 6 only
  • aria — Category 7 only
  • motion — Category 8 motion subsection
  • mobile — Category 8 mobile subsection (React Native / Flutter)
  • docs — Category 8 EAA documentation subsection (fast "are we legally exposed?" scan)

Standards:

  • wcag-2.1-aa (default) — 50 Level A + AA success criteria.
  • wcag-2.2-aa — adds 2.4.11, 2.5.8, 3.2.6, 3.3.7, 3.3.8.
  • en-301-549 — wcag-2.1-aa + mobile chapter + functional-performance statements.
  • eaa — en-301-549 + accessibility-statement documentation requirement (activates Category 8 docs).

Severity filtering: --severity high shows only HIGH, --severity warn shows HIGH+WARN, --severity info shows all. Default: all.

What This Command Does

  1. Detect framework from package.json, pubspec.yaml, and entry HTML.
  2. Scan the codebase using Grep / Glob / Read against framework-aware patterns per category in scope.
  3. Interpret findings with specific fixes tied to the detected framework.
  4. Report findings sorted by severity with WCAG / EN 301 549 citations.

Steps

Step 1: Detect Framework

Run detection before scanning. Same logic as /seo-validate plus mobile entries:

Deps / files containFrameworkNotes
nextnextApp Router uses metadata export
nuxtnuxtuseHead() / definePageMeta
astroastroislands model; client:only affects a11y
gatsbygatsbyHead API + react-helmet
@sveltejs/kitsveltekit<svelte:head>
@remix-run/*remixMetaFunction
@angular/coreangularCDK a11y module expected
vue (no nuxt)vuea11y plugins optional
react + vite (no next/remix)react-spa
react-scriptscra
react-nativereact-nativemobile — AccessibilityInfo API
pubspec.yaml with Flutter SDKfluttermobile — Semantics() widget
no framework depsstaticraw HTML

Also detect a11y libraries: @react-aria/*, @reach/*, @angular/cdk/a11y, vue-a11y, svelte-a11y, react-axe, axe-core. Their presence is INFO.

Step 2: Run Category Scans

For each category in --scope, apply the pattern set below using Grep + Read. Patterns adapt to the detected framework.

Step 3: Interpret and Enrich

For each finding:

  1. Read the flagged file/lines to confirm the match.
  2. Add a framework-specific fix (e.g., "use @react-aria/button" vs "add aria-label").
  3. Mark confidencedefinitive for regex matches, heuristic for co-occurrence / absence / target-size estimation.
  4. Skip false positives when context shows the concern is addressed (e.g., aria-label set via intl translation key).

Step 4: Report

Present findings sorted by severity (HIGH → WARN → INFO), then file path.


Scanner Reference

Category 1: Semantic Structure & Landmarks

WCAG 1.3.1 (Info and Relationships), 2.4.1 (Bypass Blocks), 2.4.6 (Headings and Labels), 3.1.1 (Language of Page), 3.1.2 (Language of Parts).

PatternSeverityConfidenceDescription
<html> missing lang attributeHIGHdefinitiveWCAG 3.1.1
Mixed-language content without <span lang="..."> wrapper (heuristic: non-Latin characters in otherwise-Latin content)WARNheuristicWCAG 3.1.2
Page/route component with >1 <h1>WARNheuristicWCAG 1.3.1
Heading level skip (h1 → h3 without h2)WARNheuristicWCAG 1.3.1
No landmark roles / semantic elements (<main>, <nav>, <header>, <footer>)WARNheuristicWCAG 1.3.1, 2.4.1
role="presentation" / role="none" on semantic elementWARNdefinitiveStrips meaning; misuse of ARIA
Multiple <main> per pageHIGHdefinitiveWCAG 1.3.1 — only one <main> allowed

Category 2: Text Alternatives & Non-Text Content

WCAG 1.1.1 (Non-text Content).

PatternSeverityConfidenceDescription
<img> without alt attributeHIGHdefinitiveWCAG 1.1.1 — required even if empty
<img alt=""> on informational image (heuristic: image inside <article>, <figure>, or with adjacent caption)WARNheuristicEmpty alt only for decorative
<img alt="image"> / <img alt="photo"> / <img alt="picture"> (redundant/meaningless)WARNdefinitiveAlt should describe content
<svg> without <title> + role="img" + aria-label, used in interactive contextWARNheuristicInline SVG needs alternative
Icon font (<i class="fa-...">, <span class="material-icons">) without aria-label or text alternativeWARNdefinitiveWCAG 1.1.1
<img> used for text content (heuristic: alt contains a full sentence like "Click here to...")WARNheuristicWCAG 1.4.5 Images of Text
Complex image (<img> with src matching `chartgraphdiagraminfographic) without long description (aria-describedbyorlongdesc` or linked description)

Category 3: Keyboard & Focus

WCAG 2.1.1 (Keyboard), 2.1.2 (No Keyboard Trap), 2.4.3 (Focus Order), 2.4.7 (Focus Visible).

PatternSeverityConfidenceDescription
tabindex value >0 (positive)HIGHdefinitiveWCAG 2.4.3 — breaks natural tab order
tabindex="-1" on natively interactive element (<button>, <a href>, <input>, etc.)WARNdefinitiveRemoves from tab order
outline: none or outline: 0 on focusable selector without :focus-visible replacementHIGHdefinitiveWCAG 2.4.7
onClick / onKeyDown handler on <div> / <span> without role="button" + tabindex="0" + keydown handler for Enter/SpaceHIGHheuristicWCAG 2.1.1 — not keyboard-accessible
No skip link (<a href="#main">, <a href="#content">) on page with navigationWARNheuristicWCAG 2.4.1 Bypass Blocks
Potential keyboard trap: event.preventDefault() / event.stopPropagation() in keydown handler on modal/dialog without Escape handlingWARNheuristicWCAG 2.1.2
Custom dropdown / combobox without aria-expanded + aria-haspopup + keyboard handlersWARNheuristicWAI-ARIA Authoring Practices
autofocus on page load on non-critical input (distracts keyboard users, moves focus unexpectedly)WARNdefinitiveConfuses assistive tech
contenteditable="true" without aria-label / aria-labelledbyWARNdefinitiveWCAG 4.1.2

Category 4: Color, Contrast & Visual Cues

WCAG 1.4.1 (Use of Color), 1.4.3 (Contrast Minimum), 1.4.11 (Non-text Contrast).

Static analysis limitation: actual contrast ratios depend on the CSS cascade, custom properties, theme switching, and background images. The skill flags patterns where contrast is AT RISK; pair with runtime tools (axe-core, Lighthouse) for definitive measurement.

PatternSeverityConfidenceDescription
Hardcoded foreground+background color pairs in CSS where computed contrast is <4.5:1 (normal) or <3:1 (large text)WARNheuristicWCAG 1.4.3 — verify at runtime
Link inside body text without underline/border AND only color distinguishing itWARNheuristicWCAG 1.4.1 — color-only signalling
Error/required field indicated only by red color (no icon, text, or shape)WARNheuristicWCAG 1.4.1
Required form field marked only with * character without aria-required="true" + text explanationWARNdefinitiveWCAG 1.4.1 + 3.3.2
CSS uses color: red/color: green as sole signal (success vs error)WARNheuristicWCAG 1.4.1
Focus indicator with <3:1 contrast against background (heuristic from color values)WARNheuristicWCAG 1.4.11
Button/input border color with <3:1 contrast against adjacent colorWARNheuristicWCAG 1.4.11
CSS text-shadow/opacity on body text reducing effective contrastINFOheuristicMay affect 1.4.3

Category 5: Forms, Labels & Errors

WCAG 1.3.5 (Identify Input Purpose), 3.3.1 (Error Identification), 3.3.2 (Labels or Instructions), 3.3.3 (Error Suggestion), 4.1.2 (Name, Role, Value).

PatternSeverityConfidenceDescription
<input> / <select> / <textarea> without <label for="..."> AND without aria-label / aria-labelledbyHIGHheuristicWCAG 3.3.2, 4.1.2
<label> without for attribute (implicit association only works if input is a child)WARNdefinitiveWCAG 3.3.2
<input type="email"/tel/name/password/address"> without autocomplete attributeWARNdefinitiveWCAG 1.3.5
Missing autocomplete="one-time-code" on OTP input with inputmode="numeric"INFOdefinitiveImproves user experience
Radio / checkbox group without <fieldset> + <legend>WARNheuristicWCAG 1.3.1
Error messages displayed visually but not linked via aria-describedby to the inputWARNheuristicWCAG 3.3.1
required attribute without accompanying aria-required="true" (belt-and-suspenders for assistive tech consistency)INFOdefinitiveWCAG 4.1.2 (modern SR handle required but legacy may not)
Error uses role="alert" without being updated dynamically (static alert on page load)INFOheuristicWCAG 4.1.3
Placeholder used as label (no visible label, only placeholder)WARNheuristicWCAG 3.3.2 — placeholder disappears on focus
<input type="email"> without inputmode="email" (mobile UX)INFOdefinitiveEN 301 549 mobile

Category 6: Media (Audio, Video, Embeds)

WCAG 1.2.1–1.2.5 (Captions, audio description, sign language), 1.4.2 (Audio Control).

EAA is specifically strict about media — video without captions is a common legal-risk finding.

PatternSeverityConfidenceDescription
<video> without <track kind="captions"> child (or <track kind="subtitles"> for foreign-language)HIGHdefinitiveWCAG 1.2.2 — EAA legal risk
<video> without transcript link or <track kind="descriptions">WARNheuristicWCAG 1.2.3 / 1.2.5
<audio> without transcript link or <track kind="captions">HIGHdefinitiveWCAG 1.2.1
<video autoplay> without mutedHIGHdefinitiveWCAG 1.4.2 — auto-playing audio
<video autoplay loop> running >5 seconds without pause controlWARNheuristicWCAG 1.4.2, 2.2.2
YouTube/Vimeo embed URL without cc_load_policy=1 or equivalent CC parameterINFOdefinitivePlatform-dependent captioning
YouTube embed via <iframe src="https://www.youtube.com/embed/..."> without accessibility enhancementsINFOdefinitiveNote: platform controls most a11y
Live media without real-time caption indicationWARNheuristicWCAG 1.2.4
Background video (hero section) without pause button in DOMWARNheuristicWCAG 2.2.2

Category 7: ARIA, Live Regions & Dynamic Content

WCAG 4.1.2 (Name, Role, Value), 4.1.3 (Status Messages).

PatternSeverityConfidenceDescription
aria-hidden="true" on focusable elementHIGHdefinitiveCreates orphaned focus — serious a11y bug
role="button" on native <button> (redundant ARIA)WARNdefinitiveARIA Authoring: avoid redundant roles
role="link" on <a href> / role="heading" on <h1–h6> (redundant ARIA)WARNdefinitiveSame
Conflicting roles (<button role="link">, <a role="button">)WARNdefinitiveWAI-ARIA — wrong role
Custom toggle (disclosure, menu, accordion) without aria-expanded + aria-controlsWARNheuristicWAI-ARIA
aria-labelledby referencing non-existent IDHIGHheuristicBroken reference
aria-describedby referencing non-existent IDHIGHheuristicBroken reference
aria-live region without role="status" / role="alert" AND async updates in component (heuristic)WARNheuristicWCAG 4.1.3
Toast/notification component without role="status" or role="alert"WARNheuristicWCAG 4.1.3
Modal / dialog without role="dialog" + aria-modal="true" + focus trapWARNheuristicWAI-ARIA Authoring Practices
Tabs without proper roles (role="tablist" + role="tab" + role="tabpanel")WARNheuristicWAI-ARIA Authoring Practices

Category 8: Motion, Target Size, Mobile & EAA Docs

8a. Motion & Animation

WCAG 2.2.2 (Pause, Stop, Hide), 2.3.3 (Animation from Interactions — AAA but EAA-recommended).

PatternSeverityConfidenceDescription
CSS animation / transition / transform without matching @media (prefers-reduced-motion: reduce) overrideWARNheuristicWCAG 2.3.3
JS animation library (GSAP, framer-motion, anime.js) without matchMedia('(prefers-reduced-motion: reduce)') checkWARNheuristicWCAG 2.3.3
Parallax scrolling without opt-outWARNheuristicWCAG 2.3.3
Infinite animation (CSS animation: name infinite) on content element without pause controlWARNheuristicWCAG 2.2.2
<marquee> / <blink> (deprecated)HIGHdefinitiveWCAG 2.2.2

8b. Target Size (WCAG 2.2 Minimum AA 2.5.8 + EN 301 549)

PatternSeverityConfidenceDescription
Interactive target with declared size <24×24 px (heuristic from CSS: width/height/padding on buttons/links/inputs)WARNheuristicWCAG 2.2 2.5.8 / EN 301 549
Touch-target spacing <8 px between adjacent interactive elementsINFOheuristicBest practice

8c. Viewport & Zoom

PatternSeverityConfidenceDescription
<meta name="viewport"> containing user-scalable=no / user-scalable=0HIGHdefinitiveWCAG 1.4.4 — blocks zoom
<meta name="viewport"> with maximum-scale=1 / maximum-scale=1.0HIGHdefinitiveWCAG 1.4.4
Content rendered via <img> for text (text-as-image)WARNheuristicWCAG 1.4.5

8d. Mobile (React Native + Flutter)

EN 301 549 mobile chapter. Critical for EAA scope since consumer apps are in-scope.

PatternSeverityConfidenceDescription
React Native: <TouchableOpacity> / <TouchableHighlight> / <Pressable> without accessibilityLabelHIGHdefinitiveEN 301 549 mobile
React Native: <Image> without accessibilityLabel or accessible={false}WARNheuristicEN 301 549
React Native: Missing accessibilityRole on custom components that behave as buttons/linksWARNheuristicEN 301 549
React Native: Alert.alert for error flow without AccessibilityInfo.announceForAccessibility fallbackINFOheuristic
Flutter: Interactive widget (GestureDetector, InkWell, TextButton, IconButton) without Semantics() wrapper or semanticLabel parameterHIGHdefinitiveEN 301 549 mobile
Flutter: Image() / Image.asset() / Image.network() without semanticLabel (or excludeFromSemantics: true for decorative)WARNdefinitiveEN 301 549
Flutter: Missing ExcludeSemantics / MergeSemantics where child semantics conflictINFOheuristicSemantics tree cleanup

8e. EAA Accessibility Documentation

Activated by --standard eaa. EAA Article 14 + member-state transpositions require consumer-facing services to publish an accessibility statement. Missing statement = HIGH legal finding.

PatternSeverityConfidenceDescription
No route at any of: /accessibility, /accessibility-statement, /a11y, /dostepnosc (PL), /barrierefreiheit (DE), /declaration-accessibilite (FR), /declaración-accesibilidad (ES), /dichiarazione-accessibilita (IT), /toegankelijkheidsverklaring (NL)HIGHheuristicEAA Article 14
Footer / sitemap lacks link to accessibility statementHIGHheuristicEAA visibility requirement
Accessibility statement present but missing required elements: (a) conformance level (WCAG/EN 301 549), (b) list of non-conformant content, (c) feedback mechanism, (d) enforcement procedure linkWARNheuristicMember-state template requirement
No contact mechanism (email / form) for accessibility feedback referenced in statementWARNheuristicEAA Article 14
robots.txt disallows /accessibility* path (accidentally blocks statement from crawlers + assistive tech)WARNdefinitiveDiscoverability

See: reference/eaa-compliance.md for directive text, member-state deadlines, statement templates.


Output Format

## Accessibility Validation Report

### Summary
| Metric | Value |
|--------|-------|
| Standard | wcag-2.1-aa / wcag-2.2-aa / en-301-549 / eaa |
| Scope | full / keyboard / contrast / forms / media / aria / motion / mobile / docs |
| Framework detected | next / nuxt / astro / ... / react-native / flutter / static |
| Files scanned | N |
| Public routes scanned | N |
| Accessibility statement | found / not-found |
| Findings: HIGH | N |
| Findings: WARN | N |
| Findings: INFO | N |

### Findings

#### [HIGH] src/components/VideoPlayer.tsx:42
Category: Media
Confidence: definitive
Pattern: `<video>` without `<track kind="captions">`
WCAG: 1.2.2 (Captions — Prerecorded, Level AA)
EAA: Article 4 (product/service accessibility requirements)
Fix: Add `<track kind="captions" src="/captions/en.vtt" srclang="en" label="English" default>`. If captions are unavailable, provide a transcript link.
See: reference/wcag-2-1-aa.md#guideline-12-time-based-media

#### [HIGH] public/index.html:8
Category: Viewport & Zoom
Confidence: definitive
Pattern: `<meta name="viewport" content="..., user-scalable=no">`
WCAG: 1.4.4 (Resize Text, Level AA)
Fix: Remove `user-scalable=no` and `maximum-scale=1` from the viewport meta — users must be able to zoom to 200%.
See: reference/wcag-2-1-aa.md#144-resize-text

#### [HIGH] src/routes.tsx:15
Category: EAA Accessibility Documentation
Confidence: heuristic
Pattern: No `/accessibility` / `/accessibility-statement` route detected; footer contains no a11y link
Standard: EAA Article 14 (mandatory accessibility statement)
Fix: Publish an accessibility statement conforming to your member-state template. Link it from the footer of every public page. See reference/eaa-compliance.md for template structure.

Confidence values:

  • definitive — regex match against a known-bad pattern.
  • heuristic — co-occurrence, absence, ordering, or derived inference (target size from CSS, contrast from hardcoded colors, ATF detection).

Exit codes (when --output json):

  • 0 — no HIGH findings.
  • 1 — one or more HIGH findings.

Out of Scope (Static Analysis Cannot Detect)

The skill explicitly does NOT verify the following — pair with runtime tools:

  • Actual contrast ratios under runtime CSS cascade, theme switching, custom properties (use axe-core, Lighthouse, or manual tooling).
  • Zoom / reflow behavior at 200% / 400% (WCAG 1.4.10, 1.4.4) — requires rendering.
  • Screen reader announcement order and quality (NVDA, JAWS, VoiceOver, TalkBack).
  • Cognitive accessibility (WCAG 3.x is mostly process/content-driven, not pattern-matchable).
  • Actual keyboard trap behavior — requires interaction.
  • Pronunciation / lang switches at runtime.
  • Real-time caption accuracy.
  • Usability / comprehension — requires user studies.

For these, use: axe-core, pa11y, Lighthouse accessibility audit, manual assistive-tech testing, and user research with disabled participants.

Rules

  • Read-only: Never modify any files.
  • Framework-aware: Detect framework first; apply correct pattern set.
  • Standards citation: Every HIGH/WARN finding cites a WCAG success criterion (e.g., "1.3.1") or EN 301 549 clause.
  • Skip non-source files: Binary files, lock files, vendored directories (node_modules/, vendor/, dist/, build/, .next/, .nuxt/, .svelte-kit/, ios/Pods/, android/build/, .dart_tool/).
  • No false confidence: Label heuristic findings clearly. Color contrast and target size are ALWAYS heuristic in static analysis.
  • EAA docs category is LEGAL risk: Missing accessibility statement when --standard eaa is selected is HIGH — this is a regulatory finding, not a code-quality suggestion.
  • No auto-fix: A11y fixes often require design/content decisions that exceed pattern matching.
  • Don't flag missing ARIA when native semantics suffice: Prefer native HTML elements; flag redundant ARIA, not absence when the native element is already there.

Reference Documents

  • reference/wcag-2-1-aa.md — All 50 Level A + AA success criteria with detection status (statically detectable vs runtime-only).
  • reference/wcag-2-2-aa.md — 9 new WCAG 2.2 success criteria (2.4.11, 2.4.12, 2.4.13, 2.5.7, 2.5.8, 3.2.6, 3.3.7, 3.3.8, 3.3.9) with failure patterns, grep patterns, and framework notes.
  • reference/eaa-compliance.md — EU Directive 2019/882 articles, EN 301 549 v3.2.1 mapping, 28 June 2025 timeline, member-state transposition deltas, accessibility-statement templates.
  • reference/aria-patterns.md — ARIA 1.2 Authoring Practices: landmarks, roles, states/properties, common anti-patterns, framework-specific helpers (@react-aria, @angular/cdk/a11y).
  • reference/mobile-eaa.md — EN 301 549 mobile chapter + React Native AccessibilityInfo / Flutter Semantics() patterns.

Related Skills

  • /seo-validate — SEO scanner; Category 9 covers a11y-for-SEO overlap only. For deep a11y compliance use /a11y-validate.
  • /cve-scan — dependency vulnerability scanner.
  • /hipaa-validate — HIPAA compliance scanner (similar pattern).

Related skills