| name | accessibility-auditor |
| description | Audit websites for accessibility issues and WCAG compliance. Use when checking accessibility, fixing a11y issues, or ensuring WCAG compliance. |
Accessibility Auditor
Instructions
When auditing accessibility:
- Run automated checks (axe, Lighthouse)
- Manual keyboard testing
- Screen reader testing
- Check WCAG criteria
- Provide fixes
Automated Testing
npx lighthouse https://yoursite.com --only-categories=accessibility --view
npx @axe-core/cli https://yoursite.com
npx pa11y https://yoursite.com
React Testing Library + jest-axe
import { render } from '@testing-library/react';
import { axe, toHaveNoViolations } from 'jest-axe';
expect.extend(toHaveNoViolations);
test('Button has no accessibility violations', async () => {
const { container } = render(<Button>Click me</Button>);
const results = await axe(container);
expect(results).toHaveNoViolations();
});
Playwright Accessibility Testing
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 }).analyze();
expect(results.violations).toEqual([]);
});
WCAG Checklist
Level A (Minimum)
Perceivable
Operable
Understandable
Robust
Level AA (Standard Target)
Common Issues & Fixes
1. Missing Alt Text
<img src="/hero.jpg" />
<img src="/hero.jpg" alt="Team collaborating in modern office" />
<img src="/decoration.jpg" alt="" role="presentation" />
<button aria-label="Close dialog">
<XIcon aria-hidden="true" />
</button>
2. Missing Form Labels
<input type="email" placeholder="Email" />
<div>
<label htmlFor="email">Email</label>
<input id="email" type="email" />
</div>
<div>
<label htmlFor="search" className="sr-only">Search</label>
<input id="search" type="search" placeholder="Search..." />
</div>
3. Poor Color Contrast
<p className="text-gray-400 bg-white">Low contrast text</p>
<p className="text-gray-700 bg-white">Accessible text</p>
4. Missing Focus Styles
*:focus { outline: none; }
*:focus-visible {
outline: 2px solid #3b82f6;
outline-offset: 2px;
}
.btn {
@apply focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2;
}
5. Non-semantic HTML
<div onClick={handleClick}>Click me</div>
<button onClick={handleClick}>Click me</button>
<div className="header">...</div>
<header>...</header>
6. Missing ARIA for Dynamic Content
<button disabled aria-busy="true">
<span className="sr-only">Loading</span>
<Spinner aria-hidden="true" />
</button>
<div aria-live="polite" aria-atomic="true">
{message && <p>{message}</p>}
</div>
<div
role="dialog"
aria-modal="true"
aria-labelledby="modal-title"
>
<h2 id="modal-title">Dialog Title</h2>
</div>
7. Skip Link
<a
href="#main-content"
className="sr-only focus:not-sr-only focus:absolute focus:top-4 focus:left-4 focus:z-50 focus:px-4 focus:py-2 focus:bg-white"
>
Skip to main content
</a>
<main id="main-content">
...
</main>
Screen Reader Only Class
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
.sr-only-focusable:focus {
position: static;
width: auto;
height: auto;
padding: inherit;
margin: inherit;
overflow: visible;
clip: auto;
white-space: normal;
}
Keyboard Testing Checklist
- Tab through page - Logical order?
- Enter/Space on buttons - Activates?
- Arrow keys in menus - Navigates?
- Escape - Closes modals/dropdowns?
- Focus visible - Always visible?
- No traps - Can tab out of all components?
Common ARIA Patterns
<div role="tablist">
<button role="tab" aria-selected="true" aria-controls="panel-1">Tab 1</button>
<button role="tab" aria-selected="false" aria-controls="panel-2">Tab 2</button>
</div>
<div role="tabpanel" id="panel-1">Content 1</div>
<div role="tabpanel" id="panel-2" hidden>Content 2</div>
<button aria-expanded="true" aria-controls="content-1">Section 1</button>
<div id="content-1">Content</div>
<button aria-haspopup="menu" aria-expanded="false">Options</button>
<ul role="menu" hidden>
<li role="menuitem">Option 1</li>
<li role="menuitem">Option 2</li>
</ul>
<div role="alert">Error: Please fix the form</div>
<div role="progressbar" aria-valuenow="50" aria-valuemin="0" aria-valuemax="100">
50%
</div>
Tools
- axe DevTools - Browser extension
- WAVE - Browser extension
- Lighthouse - Built into Chrome
- NVDA - Free Windows screen reader
- VoiceOver - Built into macOS (Cmd+F5)
- Color Contrast Analyzer - Desktop app