Accessibility Audit Skill
Perform comprehensive WCAG 2.2 accessibility audits on web components and applications.
Quick Start
import axe from 'axe-core';
// Run accessibility audit on entire page
const results = await axe.run();
// Run on specific element
const results = await axe.run(document.querySelector('#main'));
// Run with specific WCAG rules
const results = await axe.run(document, {
runOnly: { type: 'tag', values: ['wcag2aa', 'wcag21aa'] },
});
Skill Contents
Documentation
docs/wcag-guidelines.md- WCAG 2.2 levels and success criteriadocs/aria-patterns.md- Common ARIA patterns and rolesdocs/screen-readers.md- Screen reader testing guidedocs/testing-tools.md- Accessibility testing tools and setup
Examples
examples/axe-tests.ts- Vitest integration with axe-coreexamples/component-audit.tsx- Accessible React component auditexamples/keyboard-navigation.ts- Keyboard interaction patterns
Templates
templates/audit-report.md- Accessibility audit report templatetemplates/checklist.md- WCAG compliance checklist
Reference
REFERENCE.md- Quick reference cheatsheet
WCAG 2.2 Compliance Levels
| Level | Target Audience | Requirements |
|---|---|---|
| A | Minimum | Essential accessibility features |
| AA | Standard (Recommended) | Removes significant barriers |
| AAA | Enhanced | Highest level of accessibility |
Note: Most organizations target WCAG 2.2 Level AA compliance.
Comprehensive Audit Checklist
1. Perceivable
Text Alternatives (1.1)
- Images have descriptive
alttext - Decorative images have
alt="" - Complex images have extended descriptions
- Icon-only buttons have
aria-label - SVGs have
role="img"and accessible names
Time-Based Media (1.2)
- Videos have captions
- Videos have audio descriptions (if needed)
- Live audio has captions (AA)
Adaptable (1.3)
- Headings follow logical hierarchy (
<h1>→<h6>) - Lists use proper
<ul>,<ol>,<dl>elements - Tables have
<th>andscopeattributes - Form inputs have associated
<label>elements - Reading order is logical without CSS
- Instructions don't rely solely on sensory characteristics
Distinguishable (1.4)
- Color is not the only means of conveying information
- Text contrast ratio ≥ 4.5:1 (normal) or 3:1 (large)
- UI component contrast ≥ 3:1
- Text can resize to 200% without loss of content
- Images of text are avoided (except logos)
- Content reflows at 320px width without horizontal scroll
- Non-text contrast meets 3:1 ratio
- Text spacing can be adjusted without breaking layout
2. Operable
Keyboard Accessible (2.1)
- All functionality available via keyboard
- No keyboard traps (except modals with escape)
- Character key shortcuts can be disabled/remapped
Enough Time (2.2)
- Time limits can be adjusted or extended
- Moving content can be paused/stopped
- No content flashes more than 3 times per second
Navigable (2.4)
- Skip links provided for repeated blocks
- Pages have descriptive
<title> - Focus order is logical
- Link purpose is clear from text (or context)
- Multiple ways to navigate site (search, sitemap, nav)
- Headings and labels are descriptive
- Focus indicator is visible (enhanced in 2.2)
Input Modalities (2.5)
- Pointer gestures have single-pointer alternatives
- Touch targets are at least 24×24px (44×44px recommended)
- Dragging has non-dragging alternative
- Motion actuation can be disabled
3. Understandable
Readable (3.1)
- Page language declared (
<html lang="en">) - Language changes marked (
<span lang="fr">)
Predictable (3.2)
- Focus doesn't trigger unexpected changes
- Input doesn't trigger unexpected changes
- Navigation is consistent across pages
- Components are identified consistently
Input Assistance (3.3)
- Errors are identified and described
- Labels or instructions provided for inputs
- Error suggestions are provided
- Error prevention for legal/financial data
- Redundant entry assistance (new in 2.2)
- Accessible authentication (new in 2.2)
4. Robust
Compatible (4.1)
- HTML validates (no duplicate IDs)
- Name, role, value available for custom controls
- Status messages use
aria-liveregions
Automated Testing Setup
Vitest + axe-core
// vitest.setup.ts
import 'vitest-axe/extend-expect';
// Component test
import { render } from '@testing-library/react';
import { axe } from 'vitest-axe';
test('component is accessible', async () => {
const { container } = render(<MyComponent />);
const results = await axe(container);
expect(results).toHaveNoViolations();
});
Playwright + axe-core
// e2e/accessibility.spec.ts
import { test, expect } from '@playwright/test';
import AxeBuilder from '@axe-core/playwright';
test('page has no accessibility violations', async ({ page }) => {
await page.goto('/');
const results = await new AxeBuilder({ page })
.withTags(['wcag2a', 'wcag2aa', 'wcag21aa', 'wcag22aa'])
.analyze();
expect(results.violations).toEqual([]);
});
Common ARIA Patterns
Button
<!-- Native button (preferred) -->
<button type="button">Click me</button>
<!-- Custom button -->
<div role="button" tabindex="0" aria-pressed="false">Toggle</div>
Dialog/Modal
<div role="dialog" aria-modal="true" aria-labelledby="dialog-title">
<h2 id="dialog-title">Confirm Action</h2>
<p>Are you sure you want to proceed?</p>
<button>Confirm</button>
<button>Cancel</button>
</div>
Tabs
<div role="tablist" aria-label="Main sections">
<button role="tab" aria-selected="true" aria-controls="panel-1">Tab 1</button>
<button
role="tab"
aria-selected="false"
aria-controls="panel-2"
tabindex="-1"
>
Tab 2
</button>
</div>
<div role="tabpanel" id="panel-1" aria-labelledby="tab-1">Content 1</div>
<div role="tabpanel" id="panel-2" aria-labelledby="tab-2" hidden>Content 2</div>
Live Regions
<!-- Polite announcement (waits for silence) -->
<div aria-live="polite" aria-atomic="true">3 items added to cart</div>
<!-- Assertive announcement (interrupts) -->
<div aria-live="assertive" role="alert">Error: Invalid email address</div>
<!-- Status message -->
<div role="status">Loading complete</div>
Keyboard Navigation Requirements
| Component | Keys | Behavior |
|---|---|---|
| Button | Enter, Space |
Activate |
| Link | Enter |
Navigate |
| Checkbox | Space |
Toggle |
| Radio Group | ← → ↑ ↓ |
Move selection |
| Tabs | ← → |
Switch tabs |
| Menu | ↑ ↓ Enter Esc |
Navigate, select, close |
| Modal | Tab Esc |
Trap focus, close |
| Combobox | ↑ ↓ Enter Esc |
Navigate, select, close |
| Slider | ← → |
Adjust value |
Color Contrast Requirements
| Element Type | AA Ratio | AAA Ratio |
|---|---|---|
| Normal text (<18px) | 4.5:1 | 7:1 |
| Large text (≥18px or 14px bold) | 3:1 | 4.5:1 |
| UI components & graphics | 3:1 | N/A |
| Focus indicators | 3:1 | N/A |
Checking Contrast
// Using axe-core
axe.run(document, {
rules: { 'color-contrast': { enabled: true } },
});
/* CSS for ensuring focus visibility */
:focus-visible {
outline: 2px solid #0066cc;
outline-offset: 2px;
}
Audit Output Format
When asked to "audit accessibility", output a report:
# Accessibility Audit Report
**URL/Component**: [Identifier]
**Date**: [YYYY-MM-DD]
**Auditor**: [Name]
**WCAG Version**: 2.2 Level AA
**Tools Used**: axe-core, WAVE, VoiceOver/NVDA
## Executive Summary
- **Total Issues**: X
- **Critical**: X | **Serious**: X | **Moderate**: X | **Minor**: X
- **Compliance Status**: Pass / Fail / Partial
## Issues Found
### Issue 1: [WCAG Criterion] - [Impact Level]
**Element**: `<selector or description>`
**WCAG**: X.X.X (Level A/AA/AAA)
**Impact**: Critical / Serious / Moderate / Minor
**Problem**:
[Description of the accessibility barrier]
**Affected Users**:
- [ ] Screen reader users
- [ ] Keyboard users
- [ ] Low vision users
- [ ] Cognitive disabilities
**Remediation**:
- <div
* <button type="submit">Submit</button>
**Resources**:
- [Link to WCAG success criterion]
- [Link to technique]
## Testing Results
### Automated Testing
- axe-core: X violations
- Lighthouse: XX% accessibility score
### Manual Testing
- [ ] Keyboard navigation tested
- [ ] Screen reader tested (VoiceOver/NVDA)
- [ ] Zoom 200% tested
- [ ] Color contrast verified
- [ ] Motion preferences tested
## Recommendations
1. [Priority 1 fix]
2. [Priority 2 fix]
3. [Priority 3 fix]
Commands
# Run automated accessibility tests
npm run test:a11y
# Run Lighthouse accessibility audit
npx lighthouse <url> --only-categories=accessibility
# Generate detailed report
npm run audit:a11y -- --output=report.json
Screen Reader Testing
macOS VoiceOver
- Enable:
Cmd + F5 - Navigate:
Ctrl + Option + Arrow Keys - Read all:
Ctrl + Option + A - Rotor:
Ctrl + Option + U
Windows NVDA
- Enable:
Ctrl + Alt + N - Navigate:
Tab,Arrow Keys - Read all:
NVDA + Down Arrow - Elements list:
NVDA + F7
Testing Checklist
- All content is announced
- Interactive elements are identified
- Form labels are associated
- Error messages are announced
- Dynamic content updates are communicated
Resources
After Audit
[!IMPORTANT] After completing the audit, you MUST:
- Fix all critical and serious issues
- Create remediation plan for moderate/minor issues
- Run automated tests:
npm run test:a11y- Verify fixes with manual testing
- Document any exceptions with justification
Converted and distributed by TomeVault — claim your Tome and manage your conversions.