Code PushUp plugin for detecting accessibility issues using Axe š
npm install @code-pushup/axe-plugin


šµļø Code PushUp plugin for automated accessibility testing with Axe. š
---
The plugin runs accessibility audits on web pages using axe-core via Playwright. It identifies WCAG violations and best practice recommendations, providing 100+ accessibility metrics with detailed guidance for fixing problems.
Why accessibility testing matters: The European Accessibility Act (EAA) requires digital products and services in the EU to meet accessibility standards closely aligned with the Web Content Accessibility Guidelines (WCAG). This plugin provides comprehensive automated testing to help meet compliance requirements and build inclusive experiences.
1. If you haven't already, install @code-pushup/cli and create a configuration file.
2. Install as a dev dependency with your package manager:
``sh`
npm install --save-dev @code-pushup/axe-plugin
`sh`
yarn add --dev @code-pushup/axe-plugin
`sh`
pnpm add --save-dev @code-pushup/axe-plugin
3. Add this plugin to the plugins array in your Code PushUp CLI config file (e.g. code-pushup.config.ts).
Pass in the URL you want to test:
`ts
import axePlugin from '@code-pushup/axe-plugin';
export default {
// ...
plugins: [
// ...
axePlugin('https://example.com'),
],
};
`
By default, the plugin runs WCAG 2.1 Level AA audits. You can customize this using presets.
4. Run the CLI with npx code-pushup collect and view or upload the report (refer to CLI docs).
> Note: The plugin uses Playwright to run tests in Chromium. The browser will be installed automatically if not already present.
`ts`
axePlugin(urls: PluginUrls, options?: AxePluginOptions)
Parameters:
- urls - URL(s) to test. See Multiple URLs section below, or PluginUrls referenceoptions
- - Optional configuration object
Options:
| Property | Type | Default | Description |
| -------------- | ----------- | ------------ | ----------------------------------------- |
| preset | AxePreset | 'wcag21aa' | Accessibility ruleset preset |setupScript
| | string | undefined | Path to authentication setup script |scoreTargets
| | object | undefined | Pass/fail thresholds for audits or groups |
See Presets and Authentication sections below.
The plugin supports testing single or multiple URLs:
`ts
// Single URL (string)
axePlugin('https://example.com');
// Multiple URLs (array)
axePlugin(['https://example.com', 'https://example.com/about']);
// Weighted URLs (record)
axePlugin({
'https://example.com': 3, // homepage has 3x weight
'https://example.com/about': 1, // about page has 1x weight
});
`
URLs with higher weights contribute more to overall scores. For example, a URL with weight 3 has three times the influence of a URL with weight 1.
To test login-protected pages, provide a setupScript that authenticates before analysis:
`ts`
axePlugin('https://example.com/dashboard', {
setupScript: './axe-setup.ts',
});
The setup script must export a default async function that receives a Playwright Page instance:
`ts
// axe-setup.ts
import type { Page } from 'playwright-core';
export default async function (page: Page): Promise
await page.goto('https://example.com/login');
await page.fill('#username', process.env.USERNAME);
await page.fill('#password', process.env.PASSWORD);
await page.click('button[type="submit"]');
await page.waitForURL('**/dashboard');
}
`
The script runs once before analyzing URLs. Authentication state (cookies, localStorage) is automatically shared across all URL analyses.
Alternative: Cookie-based authentication
If you have a session token, you can inject it directly via cookies:
`ts
// axe-setup.ts
import type { Page } from 'playwright-core';
export default async function (page: Page): Promise
await page.context().addCookies([
{
name: 'session_token',
value: process.env.SESSION_TOKEN,
domain: 'example.com',
path: '/',
},
]);
}
`
Choose which accessibility ruleset to test against using the preset option:
`ts`
axePlugin('https://example.com', {
preset: 'wcag22aa',
});
Available presets:
| Preset | Description | Use case |
| --------------- | --------------------------------------------- | ------------------------------------- |
| wcag21aa | WCAG 2.1 Level A and AA (default) | Standard web accessibility compliance |wcag22aa
| | WCAG 2.2 Level A and AA | Latest WCAG standard |best-practice
| | Best practices (non-WCAG recommendations) | Deque's additional recommendations |all
| | All available rules | Comprehensive testing |
wcag21aa (default)
- Tests compliance with WCAG 2.1 Level A and Level AA
- Required for European Accessibility Act (EAA) compliance
- Covers fundamentals: keyboard navigation, color contrast, form labels, alt text, etc.
wcag22aa
- Tests compliance with WCAG 2.2 Level A and Level AA
- Includes all WCAG 2.1 rules plus new success criteria
- Future-proof for upcoming regulations
best-practice
- Non-WCAG recommendations from Deque Systems
- Goes beyond legal requirements
- Helps create more inclusive experiences
all
- Runs every rule available in axe-core
- Includes WCAG 2.0, 2.1, 2.2, experimental rules, and best practices
- Most comprehensive testing
> Note: Different pages may trigger different sets of rules depending on their content. For example, a page without video won't run video-related audits.
The plugin organizes audits into category groups based on axe-core's accessibility categories:
- aria - ARIAcolor
- - Color & Contrastforms
- - Formskeyboard
- - Keyboardlanguage
- - Languagename-role-value
- - Names & Labelsparsing
- - Parsingsemantics
- - Semanticssensory-and-visual-cues
- - Visual Cuesstructure
- - Structuretables
- - Tablestext-alternatives
- - Text Alternativestime-and-media
- - Media
Use npx code-pushup print-config --onlyPlugins=axe to list all audits and groups for your configuration.
The plugin provides helpers to integrate Axe results into your categories.
Use axeGroupRefs and axeAuditRefs to build categories. These helpers automatically handle multi-URL expansion:
`ts
import axePlugin, { axeGroupRefs } from '@code-pushup/axe-plugin';
const axe = axePlugin('https://example.com');
export default {
plugins: [axe],
categories: [
{
slug: 'a11y',
title: 'Accessibility',
refs: axeGroupRefs(axe),
},
],
};
`
For multi-URL setups, refs are automatically expanded for each URL with appropriate weights:
`ts
import axePlugin, { axeGroupRefs } from '@code-pushup/axe-plugin';
const axe = axePlugin({
'https://example.com': 2,
'https://example.com/about': 1,
});
export default {
plugins: [axe],
categories: [
{
slug: 'a11y',
title: 'Accessibility',
refs: axeGroupRefs(axe),
},
],
};
`
For fine-grained control, specify which groups to include:
`ts
import axePlugin, { axeGroupRefs } from '@code-pushup/axe-plugin';
const axe = axePlugin('https://example.com');
export default {
plugins: [axe],
categories: [
{
slug: 'a11y',
title: 'Accessibility',
refs: [...axeGroupRefs(axe, 'aria', 2), ...axeGroupRefs(axe, 'color'), ...axeGroupRefs(axe, 'keyboard')],
},
],
};
`
For comprehensive accessibility testing, combine Axe with Lighthouse's accessibility group in a single category:
`ts
import axePlugin, { axeGroupRefs } from '@code-pushup/axe-plugin';
import lighthousePlugin, { lighthouseGroupRefs } from '@code-pushup/lighthouse-plugin';
const urls = ['https://example.com', 'https://example.com/about'];
const axe = axePlugin(urls);
const lighthouse = await lighthousePlugin(urls);
export default {
plugins: [axe, lighthouse],
categories: [
{
slug: 'a11y',
title: 'Accessibility',
refs: [...lighthouseGroupRefs(lighthouse, 'accessibility'), ...axeGroupRefs(axe)],
},
],
};
`
This gives you both Lighthouse's performance-focused accessibility audits and Axe's comprehensive WCAG coverage in one category score.
| Function | Description |
| -------------- | -------------------------------------------------------- |
| axeGroupRefs | Creates category refs to Axe group(s), handles multi-URL |axeAuditRefs
| | Creates category refs to Axe audit(s), handles multi-URL |
> [!TIP]
> Weights determine each ref's influence on the category score. Use weight 0 to include a ref as info only, without affecting the score.
The AxeGroupSlug type is exported for discovering valid group slugs:
`ts
import type { AxeGroupSlug } from '@code-pushup/axe-plugin';
const group: AxeGroupSlug = 'aria';
`
The following helpers are deprecated and will be removed in a future version:
| Function | Replacement |
| --------------- | ------------------------------------------------- |
| axeCategories | Build categories manually with axeGroupRefs |axeGroupRef
| | Use axeGroupRefs (plural) for multi-URL support |axeAuditRef
| | Use axeAuditRefs` (plural) for multi-URL support |
- Axe-core rules - Complete list of accessibility rules
- Deque University - Detailed explanations and remediation guidance
- WCAG Guidelines - Web Content Accessibility Guidelines