Stockio

Automated Accessibility Testing With axe and Lighthouse

Combine axe state-based checks with Lighthouse page audits, triage actionable findings, and add manual verification without mistaking a clean report for WCAG conformance.

By Noor Haddad

Accessibility Specialist ·

On this page

Automated accessibility checks are most useful when they run against the same states people actually use. A clean report for an empty sign-in page says little about a checkout error, an open menu, or a completed upload. Build a repeatable workflow that catches detectable regressions early while leaving room for the questions only people can answer.

Define the scope before running a scanner

Choose representative routes, components, and states. Include an initial page, a populated form, a validation failure, a dialog, and an empty result where those patterns exist. Record the viewport, authentication state, test data, and theme. Reproducible coverage is more valuable than an impressive count of scanned URLs that all expose the same layout.

Use the contrast checker when investigating a reported text contrast failure. Enter the actual foreground and background colours and compare a proposed replacement. For layered surfaces, gradients, or transparency, first determine the rendered background at the text; copying a token name is not enough.

Read the axe-core documentation to understand the engine's results and limitations. Automated checks can detect many missing names, invalid ARIA relationships, and contrast issues, but they cannot establish that a name is meaningful or that a workflow is usable. No violations found is a statement about the checks and current state, not a certificate of accessibility.

Use Lighthouse as a page-level diagnostic

Run Lighthouse from Chrome DevTools against a stable local or preview page. Confirm the correct route and account state before collecting a report. Note whether your chosen mode reloads the page, because a reload can discard the dialog, form error, or other transient condition you intended to inspect.

The accessibility section groups detected issues and includes manual checks. Expand each finding, inspect affected elements, and follow the explanation rather than stopping at the score. A prominent label on an input may look correct but still lack a programmatic association. Fix the underlying relationship, not just the symptom highlighted in a screenshot.

The Lighthouse accessibility scoring documentation explains how the score is formed. Manual audits do not simply become passing results because the score reaches 100. Treat the score as a coarse signal for investigation, not a release requirement that replaces assessment of actual barriers.

Save useful reports with their URL, commit reference, browser version, and setup notes. When comparing runs, hold those conditions reasonably stable. Lighthouse and axe-based browser tests overlap in some checks, so agreement between them is not equivalent to two independent proofs. Their main value here is complementary workflow: quick page inspection and repeatable state coverage.

Add axe to interaction tests

A browser test can open a component, wait for its intended state, and then run axe. Use application-level signals for readiness rather than arbitrary delays. The example below assumes Playwright and the axe Playwright integration are installed and that the test project supplies a base URL.

import { test, expect } from "@playwright/test";
import AxeBuilder from "@axe-core/playwright";

test("account settings and edit dialog", async ({ page }) => {
await page.goto("/account/settings");
await expect(page.getByRole("heading", {
  name: "Account settings", exact: true
})).toBeVisible();

const initial = await new AxeBuilder({ page }).analyze();
expect(initial.violations).toEqual([]);

await page.getByRole("button", { name: "Edit profile" }).click();
await expect(page.getByRole("dialog", {
  name: "Edit profile", exact: true
})).toBeVisible();

const opened = await new AxeBuilder({ page }).analyze();
expect(opened.violations).toEqual([]);
});

The second scan matters because the dialog did not exist in the first state. State-based testing also catches error summaries, expanded disclosure panels, and results injected after a request. Configure authentication and fixtures explicitly so failures describe accessibility regressions rather than expired sessions or missing data.

The Playwright accessibility testing guide covers this integration in more detail. Scanning only a component subtree can help isolate ownership, but also run page-wide checks to catch relationships and problems outside that subtree. Do not exclude the page shell merely because it produces inconvenient results.

Triage findings without hiding the backlog

For each violation, capture the rule, affected element, interaction state, user impact, and a minimal reproduction. User impact should drive priority alongside scanner severity. A missing name on the only checkout button may block a critical task even if the total number of findings is small.

Fix shared components first when one defect appears across many routes. An icon button without a name belongs in the button component's contract, not in dozens of page-specific patches. Add a regression test that reaches the component in the failing state, then confirm the resulting accessible name is useful rather than merely nonempty.

Axe can also return results needing human review, often called incomplete results. Inspect them rather than silently discarding them because the violations array is empty. Background images, overlapping content, or uncertain contrast may require judgement. Track manual review separately so the automated assertion does not imply that every potential issue was resolved.

If an exclusion is unavoidable, make it narrow and documented. Attach an owner, reason, affected rule, and review date. Avoid blanket suppression by impact level or entire application region. A baseline can support incremental adoption, but new regressions should still fail, and existing barriers need a visible plan rather than permanent invisibility.

Pair automation with manual acceptance checks

Follow each important flow with a keyboard-only pass. Verify logical order, visible focus, operable controls, and an escape route from overlays. Then use a screen reader to check names, headings, reading order, and announcements. An automated test cannot determine whether a toast speaks twice or whether focus lands somewhere sensible after a dialog closes.

Check zoom, narrow viewports, and meaningful content changes. Long labels, missing data, and translated text can reveal clipped instructions that a default fixture misses. The WCAG interface guide provides a broader review checklist, while multi-device testing guidance helps structure viewport and browser coverage.

Define a modest initial release gate: no unreviewed new automated violations in covered critical flows, documented review of uncertain results, and completed manual checks for changed interaction patterns. Explicit limits make that gate honest. It does not assert complete WCAG conformance or replace testing with disabled people where feasible.

Keep reports and test names understandable to the next maintainer. “Edit dialog, keyboard return, validation error” describes coverage more clearly than “Accessibility passed.” Review the suite whenever a route gains a new state, and use the broader accessibility collection to identify topics your automation cannot judge.

Key takeaways

  • Use Lighthouse for page diagnostics and axe for repeatable interaction-state checks.
  • Scan realistic states with stable fixtures, not only initial page loads.
  • Prioritise user impact and keep exclusions narrow, owned, and temporary.
  • Pair clean automated reports with keyboard, screen-reader, and zoom testing.
Featured sponsor

Reach designers & developers at work

Put your product next to the tools people use every day. One sponsor per placement, no tracking pixels.

Become a sponsor

Keep reading

Related articles

More in Accessibility
Accessibility

10 Best Accessibility Courses and Learning Resources

Learn practical web accessibility through standards, tutorials, videos, and real interface examples. These ten trusted resources help beginners and working teams build skills and choose a useful next step.

Includes: Contrast checkerNoor HaddadNoor Haddad
Accessibility

10 Best Accessibility Browser Extensions for Testing

Compare ten browser add-ons for spotting accessibility issues while you browse or build, from automated page scans to heading and contrast checks, plus advice for turning findings into fixes.

Includes: Contrast checkerTheo OkaforTheo Okafor
Accessibility

12 Best Accessibility Testing Tools for Websites

Compare twelve practical accessibility testing tools, from browser extensions and automated checks to screen readers and code libraries, and learn how to choose a sensible mix for your site.

Includes: Contrast checkerNoor HaddadNoor Haddad
Accessibility

Accessible Tabs: Build a Keyboard-Friendly Tabs Component

Implement accessible tabs with correct roles, roving tabindex, manual activation, and panel relationships, then test keyboard behavior and progressive enhancement.

Includes: Contrast checkerTheo OkaforTheo Okafor
Accessibility

How to Do an Accessibility Audit and Write the Report

Scope an accessibility audit, combine automated and manual testing, and write evidence-based findings that developers can reproduce, prioritize, fix, and retest.

Includes: Contrast checkerTheo OkaforTheo Okafor
Accessibility

Focus Indicators That Meet WCAG 2.2: A Practical Guide

Create reliable keyboard focus indicators, distinguish WCAG 2.2 AA requirements from AAA appearance targets, and test contrast, clipping, and sticky overlays.

Includes: Contrast checkerNoor HaddadNoor Haddad