# Accessibility Testing Guide
Comprehensive guide for implementing accessibility testing in Next.js applications.
## Overview
Accessibility testing ensures applications are usable by people with disabilities and comply with WCAG standards.
## Tools
### axe-core
Industry-standard accessibility testing engine that detects WCAG violations.
**Installation:**
```bash
npm install -D @axe-core/playwright jest-axe
```
### @axe-core/playwright
Playwright integration for axe-core enabling E2E accessibility testing.
### jest-axe
Jest/Vitest matcher for accessibility assertions in component tests.
## Component-Level Testing
### Setup
```typescript
import { axe, toHaveNoViolations } from 'jest-axe'
expect.extend(toHaveNoViolations)
```
### Basic Usage
```typescript
it('has no accessibility violations', async () => {
const { container } = render()
const results = await axe(container)
expect(results).toHaveNoViolations()
})
```
### Testing Specific Elements
```typescript
it('form has no violations', async () => {
const { container } = render()
const form = container.querySelector('form')
const results = await axe(form)
expect(results).toHaveNoViolations()
})
```
### Custom Rules
```typescript
const results = await axe(container, {
rules: {
'color-contrast': { enabled: true },
'valid-aria-role': { enabled: true }
}
})
```
## E2E Accessibility Testing
### Setup
```typescript
import AxeBuilder from '@axe-core/playwright'
```
### Page-Level Scanning
```typescript
test('homepage meets a11y standards', async ({ page }) => {
await page.goto('/')
const accessibilityScanResults = await new AxeBuilder({ page }).analyze()
expect(accessibilityScanResults.violations).toEqual([])
})
```
### Scanning Specific Regions
```typescript
test('navigation is accessible', async ({ page }) => {
await page.goto('/')
const results = await new AxeBuilder({ page })
.include('#navigation')
.analyze()
expect(results.violations).toEqual([])
})
```
### Excluding Elements
```typescript
const results = await new AxeBuilder({ page })
.exclude('#third-party-widget')
.analyze()
```
### Custom Tags
Test specific WCAG levels:
```typescript
// WCAG 2.1 Level AA
const results = await new AxeBuilder({ page })
.withTags(['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa'])
.analyze()
```
## Common Violations and Fixes
### Missing Alt Text
**Violation:** Images without alt attributes
**Fix:**
```tsx
// Bad
// Good
// Decorative images
```
### Form Labels
**Violation:** Form inputs without labels
**Fix:**
```tsx
// Bad
// Good
// Or use aria-label
```
### Color Contrast
**Violation:** Insufficient contrast ratio
**Fix:**
- Use contrast ratio of at least 4.5:1 for normal text
- Use contrast ratio of at least 3:1 for large text
- Test with tools like WebAIM Contrast Checker
### Heading Hierarchy
**Violation:** Skipped heading levels
**Fix:**
```tsx
// Bad
Page Title
Section
// Good
Page Title
Section
```
### Keyboard Navigation
**Violation:** Interactive elements not keyboard accessible
**Fix:**
```tsx
// Bad
Click me
// Good
// Or add keyboard handlers
{
if (e.key === 'Enter' || e.key === ' ') {
handleClick()
}
}}
>
Click me
```
### Focus Indicators
**Violation:** Invisible focus indicators
**Fix:**
```css
/* Ensure visible focus */
:focus-visible {
outline: 2px solid blue;
outline-offset: 2px;
}
```
## ARIA Best Practices
### Landmarks
```tsx