Install
$ agentstack add skill-softspark-ai-toolkit-a11y-validate ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
/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 categorieskeyboard— Category 3 onlycontrast— Category 4 onlyforms— Category 5 onlymedia— Category 6 onlyaria— Category 7 onlymotion— Category 8 motion subsectionmobile— 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
- Detect framework from
package.json,pubspec.yaml, and entry HTML. - Scan the codebase using
Grep/Glob/Readagainst framework-aware patterns per category in scope. - Interpret findings with specific fixes tied to the detected framework.
- 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 contain | Framework | Notes | |---|---|---| | next | next | App Router uses metadata export | | nuxt | nuxt | useHead() / definePageMeta | | astro | astro | islands model; client:only affects a11y | | gatsby | gatsby | Head API + react-helmet | | @sveltejs/kit | sveltekit | ` | | @remix-run/* | remix | MetaFunction | | @angular/core | angular | CDK a11y module expected | | vue (no nuxt) | vue | a11y plugins optional | | react + vite (no next/remix) | react-spa | — | | react-scripts | cra | — | | react-native | react-native | mobile — AccessibilityInfo API | | pubspec.yaml with Flutter SDK | flutter | mobile — Semantics() widget | | no framework deps | static` | raw 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:
- Read the flagged file/lines to confirm the match.
- Add a framework-specific fix (e.g., "use
@react-aria/button" vs "addaria-label"). - Mark confidence —
definitivefor regex matches,heuristicfor co-occurrence / absence / target-size estimation. - 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).
| Pattern | Severity | Confidence | Description | |---------|----------|------------|-------------| | ` missing lang attribute | HIGH | definitive | WCAG 3.1.1 | | Mixed-language content without wrapper (heuristic: non-Latin characters in otherwise-Latin content) | WARN | heuristic | WCAG 3.1.2 | | Page/route component with >1 | WARN | heuristic | WCAG 1.3.1 | | Heading level skip (h1 → h3 without h2) | WARN | heuristic | WCAG 1.3.1 | | No landmark roles / semantic elements (, , , ) | WARN | heuristic | WCAG 1.3.1, 2.4.1 | | role="presentation" / role="none" on semantic element | WARN | definitive | Strips meaning; misuse of ARIA | | Multiple per page | HIGH | definitive | WCAG 1.3.1 — only one ` allowed |
Category 2: Text Alternatives & Non-Text Content
WCAG 1.1.1 (Non-text Content).
| Pattern | Severity | Confidence | Description | |---------|----------|------------|-------------| | ` without alt attribute | HIGH | definitive | WCAG 1.1.1 — required even if empty | | on informational image (heuristic: image inside , , or with adjacent caption) | WARN | heuristic | Empty alt only for decorative | | / / (redundant/meaningless) | WARN | definitive | Alt should describe content | | without + role="img" + aria-label, used in interactive context | WARN | heuristic | Inline SVG needs alternative | | Icon font (, ) without aria-label or text alternative | WARN | definitive | WCAG 1.1.1 | | used for text content (heuristic: alt contains a full sentence like "Click here to...") | WARN | heuristic | WCAG 1.4.5 Images of Text | | Complex image ( with src matching chart|graph|diagram|infographic) without long description (aria-describedby or longdesc` or linked description) | WARN | heuristic | WCAG 1.1.1 for complex content |
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).
| Pattern | Severity | Confidence | Description | |---------|----------|------------|-------------| | tabindex value >0 (positive) | HIGH | definitive | WCAG 2.4.3 — breaks natural tab order | | tabindex="-1" on natively interactive element (`, , , etc.) | WARN | definitive | Removes from tab order | | outline: none or outline: 0 on focusable selector without :focus-visible replacement | HIGH | definitive | WCAG 2.4.7 | | onClick / onKeyDown handler on / without role="button" + tabindex="0" + keydown handler for Enter/Space | HIGH | heuristic | WCAG 2.1.1 — not keyboard-accessible | | No skip link (, ) on page with navigation | WARN | heuristic | WCAG 2.4.1 Bypass Blocks | | Potential keyboard trap: event.preventDefault() / event.stopPropagation() in keydown handler on modal/dialog without Escape handling | WARN | heuristic | WCAG 2.1.2 | | Custom dropdown / combobox without aria-expanded + aria-haspopup + keyboard handlers | WARN | heuristic | WAI-ARIA Authoring Practices | | autofocus on page load on non-critical input (distracts keyboard users, moves focus unexpectedly) | WARN | definitive | Confuses assistive tech | | contenteditable="true" without aria-label / aria-labelledby` | WARN | definitive | WCAG 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.
| Pattern | Severity | Confidence | Description | |---------|----------|------------|-------------| | Hardcoded foreground+background color pairs in CSS where computed contrast is / / without AND without aria-label / aria-labelledby | HIGH | heuristic | WCAG 3.3.2, 4.1.2 | | without for attribute (implicit association only works if input is a child) | WARN | definitive | WCAG 3.3.2 | | without autocomplete attribute | WARN | definitive | WCAG 1.3.5 | | Missing autocomplete="one-time-code" on OTP input with inputmode="numeric" | INFO | definitive | Improves user experience | | Radio / checkbox group without + | WARN | heuristic | WCAG 1.3.1 | | Error messages displayed visually but not linked via aria-describedby to the input | WARN | heuristic | WCAG 3.3.1 | | required attribute without accompanying aria-required="true" (belt-and-suspenders for assistive tech consistency) | INFO | definitive | WCAG 4.1.2 (modern SR handle required but legacy may not) | | Error uses role="alert" without being updated dynamically (static alert on page load) | INFO | heuristic | WCAG 4.1.3 | | Placeholder used as label (no visible label, only placeholder) | WARN | heuristic | WCAG 3.3.2 — placeholder disappears on focus | | without inputmode="email"` (mobile UX) | INFO | definitive | EN 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.
| Pattern | Severity | Confidence | Description | |---------|----------|------------|-------------| | ` without child (or for foreign-language) | HIGH | definitive | WCAG 1.2.2 — EAA legal risk | | without transcript link or | WARN | heuristic | WCAG 1.2.3 / 1.2.5 | | without transcript link or | HIGH | definitive | WCAG 1.2.1 | | without muted | HIGH | definitive | WCAG 1.4.2 — auto-playing audio | | running >5 seconds without pause control | WARN | heuristic | WCAG 1.4.2, 2.2.2 | | YouTube/Vimeo embed URL without ccloadpolicy=1 or equivalent CC parameter | INFO | definitive | Platform-dependent captioning | | YouTube embed via ` without accessibility enhancements | INFO | definitive | Note: platform controls most a11y | | Live media without real-time caption indication | WARN | heuristic | WCAG 1.2.4 | | Background video (hero section) without pause button in DOM | WARN | heuristic | WCAG 2.2.2 |
Category 7: ARIA, Live Regions & Dynamic Content
WCAG 4.1.2 (Name, Role, Value), 4.1.3 (Status Messages).
| Pattern | Severity | Confidence | Description | |---------|----------|------------|-------------| | aria-hidden="true" on focusable element | HIGH | definitive | Creates orphaned focus — serious a11y bug | | role="button" on native ` (redundant ARIA) | WARN | definitive | ARIA Authoring: avoid redundant roles | | role="link" on / role="heading" on (redundant ARIA) | WARN | definitive | Same | | Conflicting roles (, ) | WARN | definitive | WAI-ARIA — wrong role | | Custom toggle (disclosure, menu, accordion) without aria-expanded + aria-controls | WARN | heuristic | WAI-ARIA | | aria-labelledby referencing non-existent ID | HIGH | heuristic | Broken reference | | aria-describedby referencing non-existent ID | HIGH | heuristic | Broken reference | | aria-live region without role="status" / role="alert" AND async updates in component (heuristic) | WARN | heuristic | WCAG 4.1.3 | | Toast/notification component without role="status" or role="alert" | WARN | heuristic | WCAG 4.1.3 | | Modal / dialog without role="dialog" + aria-modal="true" + focus trap | WARN | heuristic | WAI-ARIA Authoring Practices | | Tabs without proper roles (role="tablist" + role="tab" + role="tabpanel"`) | WARN | heuristic | WAI-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).
| Pattern | Severity | Confidence | Description | |---------|----------|------------|-------------| | CSS animation / transition / transform without matching @media (prefers-reduced-motion: reduce) override | WARN | heuristic | WCAG 2.3.3 | | JS animation library (GSAP, framer-motion, anime.js) without matchMedia('(prefers-reduced-motion: reduce)') check | WARN | heuristic | WCAG 2.3.3 | | Parallax scrolling without opt-out | WARN | heuristic | WCAG 2.3.3 | | Infinite animation (CSS animation: name infinite) on content element without pause control | WARN | heuristic | WCAG 2.2.2 | | ` / ` (deprecated) | HIGH | definitive | WCAG 2.2.2 |
8b. Target Size (WCAG 2.2 Minimum AA 2.5.8 + EN 301 549)
| Pattern | Severity | Confidence | Description | |---------|----------|------------|-------------| | Interactive target with declared size containing user-scalable=no / user-scalable=0 | HIGH | definitive | WCAG 1.4.4 — blocks zoom | | with maximum-scale=1 / maximum-scale=1.0 | HIGH | definitive | WCAG 1.4.4 | | Content rendered via ` for text (text-as-image) | WARN | heuristic | WCAG 1.4.5 |
8d. Mobile (React Native + Flutter)
EN 301 549 mobile chapter. Critical for EAA scope since consumer apps are in-scope.
| Pattern | Severity | Confidence | Description | |---------|----------|------------|-------------| | React Native: ` / / without accessibilityLabel | HIGH | definitive | EN 301 549 mobile | | **React Native**: without accessibilityLabel or accessible={false} | WARN | heuristic | EN 301 549 | | **React Native**: Missing accessibilityRole on custom components that behave as buttons/links | WARN | heuristic | EN 301 549 | | **React Native**: Alert.alert for error flow without AccessibilityInfo.announceForAccessibility fallback | INFO | heuristic | — | | **Flutter**: Interactive widget (GestureDetector, InkWell, TextButton, IconButton) without Semantics() wrapper or semanticLabel parameter | HIGH | definitive | EN 301 549 mobile | | **Flutter**: Image() / Image.asset() / Image.network() without semanticLabel (or excludeFromSemantics: true for decorative) | WARN | definitive | EN 301 549 | | **Flutter**: Missing ExcludeSemantics / MergeSemantics` where child semantics conflict | INFO | heuristic | Semantics 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.
| Pattern | Severity | Confidence | Description | |---------|----------|------------|-------------| | No route at any of: /accessibility, /accessibility-statement, /a11y, /dostepnosc (PL), /barrierefreiheit (DE), /declaration-accessibilite (FR), /declaración-accesibilidad (ES), `/dichiarazio
…
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: softspark
- Source: softspark/ai-toolkit
- License: MIT
- Homepage: https://softspark.eu
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.