Skip to content

Accessibility Testing

Accessibility testing checks that people using assistive technology — screen readers, keyboards, switch devices, magnification — can use the interface. The reference standard is WCAG, organised around four principles.

Perceivable ─ can I take it in? (alt text, contrast, captions)
Operable ─ can I drive it? (keyboard, focus, no traps)
Understandable ─ do I get it? (labels, errors, consistency)
Robust ─ does it work with AT? (semantics, valid ARIA)

Automated tools catch roughly a third of issues. The rest needs a keyboard, a screen reader, and real people.

Use it for

  • Any user-facing UI, especially forms, navigation and interactive widgets
  • Every PR: a cheap automated scan (axe) in CI catches regressions
  • Before release: a manual keyboard and screen-reader pass on key flows
  • Legal or procurement requirements that mandate WCAG 2.2 AA conformance

Avoid or reduce it when

  • You rely on an automated scan alone and call it “accessible”
  • The control has no semantic equivalent (a canvas-only UI) without a fallback
  • You test only the happy path and skip error states and empty states
  • You ignore focus order and let the keyboard user get trapped
Tool Ecosystem Notes
axe-core JS/TS, browser The engine behind many tools; rules tagged by WCAG level
jest-axe JS/TS tests Assert no violations in component tests
pa11y Node CLI Scriptable page checks, CI-ready
Lighthouse Chrome Accessibility score within a broader audit
WAVE Browser ext / API Visual overlay of issues on the page
Accessibility Insights Browser ext Guided manual checks plus automated
NVDA / VoiceOver Screen readers Free, essential for manual testing
HTML validator Any A valid document is a robust document
Terminal window
npm install -D axe-core @axe-core/playwright jest-axe vitest-axe
// in a component test
import { axe } from 'vitest-axe';
import AxeBuilder from '@axe-core/playwright';
import { test, expect } from '@playwright/test';
test('home page has no accessibility violations', async ({ page }) => {
await page.goto('/');
const results = await new AxeBuilder({ page })
.withTags(['wcag2a', 'wcag2aa'])
.analyze();
expect(results.violations).toEqual([]);
});
  • Automate the detectable, test the rest by hand. Tools are a floor, not a ceiling.
  • Use semantic HTML first. A <button> beats a <div role="button"> you must keep patching with ARIA.
  • Check colour contrast with real values. Many “designed” greys fail 4.5:1.
  • Test the keyboard-only path. Tab order, visible focus, no traps, skip links.
  • Give images real alt text. Decorative images take alt=""; icons carrying meaning need a name.
  • Include people with disabilities. Automated checks plus screen-reader users find what neither finds alone.

Self-assessment quiz

Pick one answer per question, then press Check answers.

  1. What do the four WCAG principles spell (POUR)?
  2. An automated accessibility scan finds roughly what share of issues?
  3. Which is a common automated accessibility engine used by many tools?
  4. What minimum contrast ratio does WCAG AA require for normal text?
  5. Why prefer a native button over a div with role="button"?