Accessibility Auditor
Audit web applications for WCAG 2.0/2.1/2.2 compliance by identifying common violations and providing actionable remediation steps.
When to Use
- User requests accessibility audit, a11y check, or WCAG compliance review
- User mentions accessibility issues, screen readers, or keyboard navigation problems
- User asks to check or improve accessibility for people with disabilities
WCAG Principles: POUR
| Principle | Description |
|---|---|
| Perceivable | Content can be perceived through different senses |
| Operable | Interface can be operated by all users |
| Understandable | Content and interface are understandable |
| Robust | Content works with assistive technologies |
Conformance Levels
| Level | Requirement | Target |
|---|---|---|
| A | Minimum accessibility | Must pass |
| AA | Standard compliance | Should pass (legal requirement in many jurisdictions) |
| AAA | Enhanced accessibility | Nice to have |
12 Most Common WCAG Violations
Based on WebAIM Million (2021) research analyzing top 1M websites:
- Low Color Contrast (WCAG 1.4.3) - 86.4% of sites
- Text < 4.5:1 contrast ratio - Large text < 3:1 contrast ratio - UI components < 3:1
- Missing/Inadequate Alt Text (WCAG 1.1.1) - 60.6% of sites
- Images without alt attribute - Alt text with "image", "picture", "photo" - Empty alt on meaningful images
- Missing Name, Role, or Value (WCAG 4.1.2)
- Interactive elements without accessible names - Custom components without proper ARIA - Buttons, form fields, custom widgets
- Keyboard Navigation Failures (WCAG 2.1.1)
- Elements with onClick but not keyboard accessible - Missing focus indicators - Trapped keyboard focus
- Unlabeled Form Controls (WCAG 1.3.1, 3.3.2) - 39.6% of sites
- Inputs without <label> or aria-label - Labels not programmatically associated
- Missing Language Attributes (WCAG 3.1.1) - 28.9% of sites
- No lang attribute on <html> - Missing lang for foreign language passages
- Improper Heading Structure (WCAG 1.3.1, 2.4.6)
- Skipped heading levels (h1 → h3) - Multiple h1s or no h1 - Empty headings
- Empty Links or Poor Link Text (WCAG 2.4.4)
- Links with "click here", "here", "read more" - Empty links or links with only icons
- Missing/Improper Focus Indicators (WCAG 2.4.7)
- CSS removing outline without replacement - Insufficient focus indicator contrast
- Overuse/Misuse of ARIA (WCAG 4.1.2)
- Unnecessary ARIA when native HTML works - Invalid ARIA attributes for roles - Required ARIA attributes missing
- Inadequate Data Table Markup (WCAG 1.3.1)
- Tables without <th> elements - Missing scope or headers attributes
- Missing Media Captions (WCAG 1.2.1, 1.2.2)
- Videos without captions/subtitles - Audio without transcripts
Audit Process
Phase 1: Automated Testing
Run ESLint (React/JSX projects):
npx eslint --ext .jsx,.tsx --no-ignore --format json . > .claude/skills/a11y-auditor/eslint-results.json 2>&1 || trueOr use helper script: .claude/skills/a11y-auditor/scripts/run-eslint.sh
Run Lighthouse (production/staging):
npx lighthouse https://example.com --only-categories=accessibility --output=json --output-path=./lighthouse-results.jsonCheck for axe-core integration:
grep -r "@axe-core\|axe-core" package.jsonPhase 2: Manual Code Inspection
Use grep patterns from references/grep-patterns.md to search for:
- Missing alt text
- Keyboard navigation issues
- Color values for contrast checking
- ARIA issues
- Form labels
- Heading structure
- Language attributes
- Poor link text
- Media elements
See references/grep-patterns.md for complete pattern list.
Phase 3: Analyze & Prioritize
Group findings by severity using WCAG impact levels:
Critical (fix immediately):
- Keyboard traps
- No focus indicators
- Missing form labels
- Missing alt text on functional images
- Insufficient color contrast on interactive elements
Serious (fix before launch):
- Missing page language
- Improper heading structure
- Non-descriptive link text
- Missing skip links
- Auto-playing media
Moderate (fix soon):
- Missing ARIA labels on icons
- Inconsistent navigation
- Missing error identification
- Missing landmark regions
Phase 4: Manual Testing
Follow references/screen-reader-guide.md for:
- Keyboard navigation testing
- Screen reader testing (VoiceOver, NVDA, JAWS)
- Zoom and reflow testing
- High contrast mode testing
- Reduced motion testing
WCAG Pattern Examples
Perceivable
Alt Text (1.1.1)
<!-- ❌ Missing alt -->
<img src="chart.png">
<!-- ✅ Descriptive alt -->
<img src="chart.png" alt="Bar chart showing 40% increase in Q3 sales">
<!-- ✅ Decorative (empty alt) -->
<img src="decorative-border.png" alt="" role="presentation">Color Contrast (1.4.3)
/* ❌ Low contrast (2.5:1) */
.low-contrast {
color: #999;
background: #fff;
}
/* ✅ Sufficient contrast (7:1) */
.high-contrast {
color: #333;
background: #fff;
}Contrast requirements:
- Normal text: 4.5:1 (AA), 7:1 (AAA)
- Large text (18px+ or 14px+ bold): 3:1 (AA), 4.5:1 (AAA)
- UI components: 3:1
Media Alternatives (1.2)
<video controls>
<source src="video.mp4" type="video/mp4">
<track kind="captions" src="captions.vtt" srclang="en" label="English" default>
</video>Operable
Keyboard Navigation (2.1.1)
// ❌ Only click
element.addEventListener('click', handleAction);
// ✅ Click + keyboard
element.addEventListener('click', handleAction);
element.addEventListener('keydown', (e) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
handleAction();
}
});Focus Visible (2.4.7)
/* ❌ Never remove focus */
*:focus { outline: none; }
/* ✅ Keyboard-only focus */
:focus-visible {
outline: 2px solid #005fcc;
outline-offset: 2px;
}Skip Links (2.4.1)
<body>
<a href="#main-content" class="skip-link">Skip to main content</a>
<header><!-- navigation --></header>
<main id="main-content" tabindex="-1">
<!-- content -->
</main>
</body>.skip-link {
position: absolute;
top: -40px;
left: 0;
background: #000;
color: #fff;
padding: 8px 16px;
z-index: 100;
}
.skip-link:focus {
top: 0;
}Reduced Motion (2.3.3)
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}Understandable
Page Language (3.1.1)
<!-- ❌ No language -->
<html>
<!-- ✅ Language specified -->
<html lang="en">
<!-- ✅ Language changes -->
<p>The French word for hello is <span lang="fr">bonjour</span>.</p>Form Labels (3.3.2)
<!-- ❌ No label -->
<input type="email" placeholder="Email">
<!-- ✅ Explicit label -->
<label for="email">Email address</label>
<input type="email" id="email" autocomplete="email">
<!-- ✅ With hint -->
<label for="password">Password</label>
<input type="password" id="password" aria-describedby="password-requirements">
<p id="password-requirements">
Must be at least 8 characters with one number.
</p>Error Handling (3.3.1)
<label for="email">Email</label>
<input type="email" id="email"
aria-invalid="true"
aria-describedby="email-error">
<p id="email-error" role="alert">
Please enter a valid email address.
</p>Robust
ARIA Usage (4.1.2)
<!-- ❌ Unnecessary ARIA -->
<button role="button">Submit</button>
<!-- ✅ Native HTML -->
<button>Submit</button>
<!-- ✅ ARIA when needed (custom tabs) -->
<div role="tablist" aria-label="Product information">
<button role="tab" aria-selected="true" aria-controls="panel-1">
Description
</button>
<button role="tab" aria-selected="false" aria-controls="panel-2" tabindex="-1">
Reviews
</button>
</div>
<div role="tabpanel" id="panel-1" aria-labelledby="tab-1">
<!-- content -->
</div>Live Regions (4.1.3)
<!-- Polite (waits for pause) -->
<div aria-live="polite" aria-atomic="true">
Status update
</div>
<!-- Assertive (interrupts) -->
<div role="alert" aria-live="assertive">
Error: Form submission failed
</div>Visually Hidden Text
.visually-hidden {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}<button>
<svg aria-hidden="true"><!-- icon --></svg>
<span class="visually-hidden">Delete item</span>
</button>Output Format
Generate reports structured as:
# Accessibility Audit Report
## Summary
- Total Issues: X
- Critical: X | Serious: X | Moderate: X | Minor: X
- WCAG Level: A, AA, or AAA
- Automated Coverage: ~57% (manual testing required)
## Critical Issues (Fix Immediately)
### 1. [Issue Name] - WCAG X.X.X
**Severity:** Critical
**Impact:** [Who is affected and how]
**Affected:** X elements
**Locations:**
- `path/to/file.tsx:123`
- `path/to/file.tsx:456`
**Problem:**
[Brief description]
**Fix:**// Before <div onClick={handleClick}>Click me</div>
// After <button onClick={handleClick}>Click me</button>
**Why:** [Accessibility principle]
---
## Serious Issues
[Same format]
## Moderate Issues
[Same format]
## Testing Recommendations
1. Manual keyboard testing (Tab, Enter, Escape)
2. Screen reader testing (see references/screen-reader-guide.md)
3. Automated testing setup (@axe-core/react or Lighthouse CI)
4. Color contrast validation (WebAIM Contrast Checker)
## Next Steps
[Prioritized action items]
Tools & Resources
Development Tools
- eslint-plugin-jsx-a11y - React/JSX static analysis (~37 rules)
- axe-core DevTools - Browser extension for runtime testing
- Lighthouse - Built into Chrome DevTools
Testing Tools
- @axe-core/react - Runtime accessibility testing
- @axe-core/playwright - E2E test integration
- pa11y - Automated command-line testing
Manual Testing
- WebAIM Contrast Checker - https://webaim.org/resources/contrastchecker/
- WAVE - Browser extension for visual feedback
- Screen readers - NVDA (Windows), VoiceOver (macOS), JAWS
Reference Docs
references/WCAG-criteria.md- All WCAG 2.1 success criteriareferences/ARIA-patterns.md- Common ARIA patterns and examplesreferences/screen-reader-guide.md- Testing commands and scenariosreferences/grep-patterns.md- Search patterns for code audits
References
- WebAIM Million - Annual analysis of top 1M websites (violation statistics)
- WCAG 2.1 Quick Reference - Interactive WCAG guide
- WAI-ARIA Authoring Practices - Official ARIA patterns
- Deque axe Rules - All axe-core rules explained
- jsx-a11y Rules - ESLint accessibility rules
Important Notes
- Automated tools catch 30-57% of issues; manual testing required
- Pages with ARIA average 41% more errors than without
- Always test with actual assistive technology when possible
- Focus on critical issues first (keyboard, screen readers, contrast)
- Document deliberate accessibility decisions
- Test on multiple browsers and devices
- Include users with disabilities in testing when possible
Common Pitfalls to Avoid
- Relying solely on automated testing
- Using ARIA when native HTML suffices
- Removing focus indicators
- Using positive tabindex values
- Color as only means of conveying information
- Keyboard traps in modals/dialogs
- Non-descriptive link text
- Missing or incorrect heading hierarchy
- Unlabeled form controls
- Missing language attributes