
A11y Audit
Audit React (or similar) UI for WCAG issues—missing labels, keyboard traps, contrast, and semantic HTML—before you ship a solo SaaS or marketing site.
Overview
a11y-audit is an agent skill most often used in Ship (also Build frontend) that scans UI code for WCAG-oriented accessibility failures such as contrast, semantics, and keyboard support.
Install
npx skills add https://github.com/alirezarezvani/claude-skills --skill a11y-auditWhat is this skill?
- Flags common React a11y smells—clickable divs, images without alt, placeholder-only inputs, tables without proper header
- Computes contrast ratios against WCAG AA (4.5:1 normal text) and AAA (7:1) thresholds with explicit pass/fail
- Surfaces keyboard and semantics issues such as improper tab order and non-interactive elements acting as controls
- Works as a checker on existing components rather than generating greenfield UI from scratch
- WCAG AA normal text contrast threshold 4.5:1
- WCAG AAA normal text contrast threshold 7.0:1
Adoption & trust: 606 installs on skills.sh; 17.5k GitHub stars; 3/3 security scanners passed (skills.sh audits).
What problem does it solve?
You shipped fast UI that looks fine visually but you are not sure it meets contrast, screen-reader, or keyboard requirements.
Who is it for?
Indie builders polishing React or web components before launch or after a design refresh who need structured a11y feedback.
Skip if: Teams that only need brand/visual critique with no compliance goal, or native-only apps where this skill’s web-component patterns do not apply.
When should I use this skill?
You want to review UI components for accessibility violations, contrast ratios, or keyboard/semantic HTML issues before shipping.
What do I get? / Deliverables
You get a concrete list of accessibility issues and ratio checks you can fix in code before release.
- Issue list mapped to components
- Contrast ratio report with AA/AAA pass or fail
Recommended Skills
Journey fit
Spans multiple journey phases - primary shelf plus alternate fits below.
Accessibility audits belong on the Ship shelf because they gate quality and compliance right before launch, even though you can run them while still editing UI in Build. Review is the canonical subphase: the skill compares components against WCAG expectations and reports failures (contrast, roles, focus) like a structured pre-release review pass.
Where it fits
After adding a user card with icon-only actions, run the skill to catch missing names and clickable divs.
Before merging a release branch, audit tables and search UI for header semantics and focus order.
Validate that status indicators are not color-only and that form fields have accessible labels.
Pre-check marketing or in-app webviews that must meet store accessibility expectations.
How it compares
Use as a focused accessibility checker instead of generic “make it prettier” design feedback.
Common Questions / FAQ
Who is a11y-audit for?
Solo and indie developers shipping web or React UI who want WCAG-oriented checks without a dedicated accessibility consultant on retainer.
When should I use a11y-audit?
During Ship review before launch, after Build frontend changes to forms and tables, and when validating a landing page or dashboard for contrast and keyboard use.
Is a11y-audit safe to install?
Review the Security Audits panel on this Prism page and only grant filesystem access to repos you trust; the skill inspects local code rather than calling external audit APIs in the sample material.
SKILL.md
READMESKILL.md - A11y Audit
// Sample React component with intentional a11y issues for testing import React from 'react'; export function UserCard({ user, onEdit, onDelete }) { return ( <div className="card" onClick={() => onEdit(user.id)}> <img src={user.avatar} /> <div className="name">{user.name}</div> <div className="email">{user.email}</div> <div className="actions"> <div onClick={() => onDelete(user.id)} style={{ color: '#aaa', cursor: 'pointer' }}> Delete </div> <a href="#">Edit</a> </div> <input placeholder="Add note" /> </div> ); } export function SearchBar() { return ( <div> <input type="text" placeholder="Search..." /> <div onClick={() => alert('searching')} tabIndex={5}> 🔍 </div> </div> ); } export function DataTable({ rows }) { return ( <table> <tr> <td><b>Name</b></td> <td><b>Email</b></td> <td><b>Status</b></td> </tr> {rows.map((row) => ( <tr key={row.id}> <td>{row.name}</td> <td>{row.email}</td> <td style={{ color: row.active ? 'green' : 'red' }}> {row.active ? '●' : '●'} </td> </tr> ))} </table> ); } Contrast Check: #777777 on #ffffff Foreground: #777777 (r=119, g=119, b=119) Background: #ffffff (r=255, g=255, b=255) Contrast Ratio: 4.48:1 Normal text (4.5:1 required): AA: FAIL (4.48 < 4.5) AAA: FAIL (4.48 < 7.0) Large text (3.0:1 required): AA: PASS (4.48 >= 3.0) AAA: FAIL (4.48 < 4.5) UI components (3.0:1 required): AA: PASS (4.48 >= 3.0) Verdict: FAIL — does not meet AA for normal text --- Contrast Check: #1a1a2e on #ffffff Foreground: #1a1a2e (r=26, g=26, b=46) Background: #ffffff (r=255, g=255, b=255) Contrast Ratio: 17.06:1 Normal text (4.5:1 required): AA: PASS AAA: PASS Large text (3.0:1 required): AA: PASS AAA: PASS UI components (3.0:1 required): AA: PASS Verdict: PASS — meets AAA for all categories { "summary": { "files_scanned": 1, "files_with_issues": 1, "total_issues": 9, "critical": 3, "serious": 4, "moderate": 2, "minor": 0, "verdict": "FAIL" }, "findings": [ { "severity": "critical", "category": "IMG-ALT", "file": "sample-component.tsx", "line": 7, "code": "<img src={user.avatar} />", "wcag": "1.1.1", "message": "Image missing alt attribute", "fix": "Add alt text: alt=\"description of image\"" }, { "severity": "critical", "category": "KB-CLICK", "file": "sample-component.tsx", "line": 5, "code": "<div className=\"card\" onClick={() => onEdit(user.id)}>", "wcag": "2.1.1", "message": "Click handler on non-interactive element without keyboard support", "fix": "Use <button> or add role=\"button\", tabIndex={0}, onKeyDown" } ] } # A11y Audit Report — sample-component.tsx **Scanned:** 1 file | **Issues:** 9 | **Status:** FAIL ## Critical (3) ### 1. Missing alt text on image - **File:** sample-component.tsx:7 - **Code:** `<img src={user.avatar} />` - **WCAG:** 1.1.1 Non-text Content (Level A) - **Fix:** Add descriptive alt text: `<img src={user.avatar} alt={`${user.name}'s avatar`} />` ### 2. Click handler without keyboard support - **File:** sample-component.tsx:5 - **Code:** `<div className="card" onClick={() => onEdit(user.id)}>` - **WCAG:** 2.1.1 Keyboard (Level A) - **Fix:** Use `<button>` or add `role="button"`, `tabIndex={0}`, and `onKeyDown` ### 3. Click handler without keyboard support - **File:** sample-component.tsx:11 - **Code:** `<div onClick={() => onDelete(user.id)} ...>` - **WCAG:** 2.1.1 Keyboard (Level A) - **Fix:** Replace `<div>` with `<button>` ## Serious (4) ### 4. Missing form label - **File:** sample-component.tsx:15 - **Code:** `<input placeholder="Add note" />` - **WCAG:** 3.3.2 Labels or Instructions (Level