Built from scratch (replaces reverted PR #375 contribution). Skill package: - SKILL.md: 1132 lines, 3-phase workflow (scan → fix → verify), per-framework fix patterns (React, Next.js, Vue, Angular, Svelte, HTML), CI/CD integration guide, 20+ issue type coverage - scripts/a11y_scanner.py: static scanner detecting 20+ violation types across HTML/JSX/TSX/Vue/Svelte/CSS — severity-ranked, CI-friendly exit codes - scripts/contrast_checker.py: WCAG contrast calculator with AA/AAA checks, --suggest mode, --batch CSS scanning, named color support - references/wcag-quick-ref.md: WCAG 2.2 Level A/AA criteria table - references/aria-patterns.md: ARIA roles, live regions, keyboard interaction - references/framework-a11y-patterns.md: React, Vue, Angular, Svelte fix patterns - assets/sample-component.tsx: sample file with intentional violations - expected_outputs/: scan report, contrast output, JSON output samples - /a11y-audit slash command, settings.json, plugin.json, README.md Validation: 97.6/100 (EXCELLENT), quality 73.9/100 (B-), scripts 2/2 PASS Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
64 lines
2.2 KiB
Markdown
64 lines
2.2 KiB
Markdown
# 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 A)
|
|
- **Fix:** Add `<label>` or `aria-label="Add note"`
|
|
|
|
### 5. Empty link
|
|
- **File:** sample-component.tsx:14
|
|
- **Code:** `<a href="#">Edit</a>`
|
|
- **WCAG:** 2.4.4 Link Purpose (Level A)
|
|
- **Fix:** Use a real href or replace with `<button>`
|
|
|
|
### 6. tabindex greater than 0
|
|
- **File:** sample-component.tsx:24
|
|
- **Code:** `tabIndex={5}`
|
|
- **WCAG:** 2.4.3 Focus Order (Level A)
|
|
- **Fix:** Use `tabIndex={0}` — positive values disrupt natural tab order
|
|
|
|
### 7. Missing table headers
|
|
- **File:** sample-component.tsx:30
|
|
- **Code:** `<td><b>Name</b></td>` (using td+b instead of th)
|
|
- **WCAG:** 1.3.1 Info and Relationships (Level A)
|
|
- **Fix:** Use `<th scope="col">Name</th>`
|
|
|
|
## Moderate (2)
|
|
|
|
### 8. Missing form label
|
|
- **File:** sample-component.tsx:22
|
|
- **Code:** `<input type="text" placeholder="Search..." />`
|
|
- **WCAG:** 3.3.2 Labels or Instructions (Level A)
|
|
- **Fix:** Add `aria-label="Search"` or visible label
|
|
|
|
### 9. Color as sole indicator
|
|
- **File:** sample-component.tsx:38
|
|
- **Code:** `style={{ color: row.active ? 'green' : 'red' }}`
|
|
- **WCAG:** 1.4.1 Use of Color (Level A)
|
|
- **Fix:** Add text or icon alongside color: `{row.active ? '✓ Active' : '✗ Inactive'}`
|