SuperAPI AI Directory

axe-rules

Testing & quality

View repository

Updated 10-16 00:29

About this skill

Axe-Core Rules Reference Skill

Canonical source: examples/AXE_RULES_REFERENCE.md and examples/AXE_RULES_COVERAGE.md in mgifford/ACCESSIBILITY.md This skill is derived from those files. When in doubt, the example is authoritative. Note: the canonical files are organized around a specific test-fixture scanner project (numbered test pages). This skill re-presents the same rule set and severities as a general-purpose reference, independent of any particular fixture.

Apply these rules when writing, reviewing, or debugging axe-core scans.


Core Principle

Axe-core catches ~30–40% of WCAG issues automatically. It is the baseline, not the ceiling. Always pair automated scanning with manual keyboard and screen reader testing.

An axe-core result is evidence, not a conformance decision. Preserve the rule's raw outcome (violations, incomplete, passes, inapplicable) exactly as axe reports it — do not overwrite or discard it when converting to a project finding. Cite this file, AXE_RULES_REFERENCE.md, or the rule's own dequeuniversity.com/rules/axe/ page as the authority for a WCAG mapping; do not invent a mapping axe-core does not document for that rule. Record an unreviewed violations result as evidence_status: automated-indicator with handling: review — never as a confirmed standards failure — until a human confirms it. See Accessibility Finding Tracking: Policy Classification.

Key tags to include in scans:

.withTags(['wcag2a', 'wcag2aa', 'wcag21aa', 'wcag22aa'])

Axe-core 4.11 includes 100+ automated checks across these categories: WCAG 2.0 A/AA (68 rules), WCAG 2.1 A/AA (26 rules), WCAG 2.2 A/AA (1 rule, disabled by default), Best Practices (30+ rules), WCAG AAA (3 rules, disabled by default), Experimental (9 rules, disabled by default), and Deprecated (7 rules, disabled by default).


Severity Scale (axe-core)

axe severity Meaning
critical Blocks access for one or more disability groups
serious Significantly impairs access
moderate Creates friction; workaround exists
minor Best-practice gap; marginal impact

Critical Rules — must never appear in production

Rule ID Category Description
image-alt Text alternatives <img> missing alt attribute
area-alt Text alternatives Image map <area> missing alt text
input-image-alt Text alternatives <input type="image"> missing alt
video-caption Text alternatives <video> without captions
aria-allowed-attr ARIA Element has unsupported ARIA attributes for its role
aria-hidden-body ARIA aria-hidden applied to <body>
aria-required-attr ARIA Required ARIA attribute missing
aria-required-children ARIA Required child ARIA roles missing
aria-required-parent ARIA Required parent ARIA role missing
aria-roles ARIA Invalid ARIA role value
aria-valid-attr ARIA Invalid ARIA attribute name
aria-valid-attr-value ARIA ARIA attribute has invalid value
label Forms Form input without associated <label>
select-name Forms <select> without accessible name
button-name Buttons/Links Button without discernible text
input-button-name Buttons/Links <input type="button"> without text
duplicate-id-aria Structure Duplicate id values referenced by ARIA
meta-refresh Meta <meta http-equiv="refresh"> causes timed redirect

Serious Rules — fix before release

Rule ID Category Description
object-alt Text alternatives <object> without accessible text
svg-img-alt Text alternatives SVG with role="img" and no accessible name
role-img-alt Text alternatives Element with role="img" lacks alt text
aria-braille-equivalent ARIA Braille label without non-braille equivalent
aria-command-name ARIA Button, link, or menu item without accessible name
aria-conditional-attr ARIA ARIA attribute used contrary to role spec
aria-hidden-focus ARIA aria-hidden element contains focusable content
aria-input-field-name ARIA ARIA input field without accessible name
aria-meter-name ARIA ARIA meter element without accessible name
aria-progressbar-name ARIA ARIA progressbar element without accessible name
aria-prohibited-attr ARIA Prohibited ARIA attribute used
aria-toggle-field-name ARIA ARIA toggle field without accessible name
aria-tooltip-name ARIA ARIA tooltip without accessible name
aria-dialog-name ARIA Dialog without accessible name
aria-treeitem-name ARIA Tree item without accessible name
color-contrast Color Text contrast below 4.5:1 (normal) or 3:1 (large)
frame-title Frames <iframe> without accessible name
frame-title-unique Frames Frame titles are not unique
frame-focusable-content Frames Frame with focusable content is tabindex="-1"
html-has-lang Language <html> missing lang attribute
html-lang-valid Language lang attribute has invalid BCP 47 value
valid-lang Language Inline lang value is invalid
document-title Language <title> element missing
list Structure <ul>/<ol> contains elements other than <li>
listitem Structure <li> outside <ul> or <ol>
definition-list Structure <dl> contains elements other than <dt>/<dd>
dlitem Structure <dt>/<dd> outside <dl>
bypass Keyboard No skip navigation mechanism present
scrollable-region-focusable Keyboard Scrollable region not keyboard accessible
link-name Buttons/Links Link without discernible text
link-in-text-block Buttons/Links Link not distinguishable from surrounding text
avoid-inline-spacing Content sizing Text spacing overrides not adjustable
autocomplete-valid Forms autocomplete attribute invalid or missing
tabindex Best practices tabindex value > 0 used
label-title-only Best practices Form field labeled only via title attribute
label-content-name-mismatch Best practices (experimental) Visible label text doesn't match accessible name
td-has-header Tables (experimental) Large table cells lack associated headers
table-fake-caption Tables (experimental) Table caption not marked up with <caption>
p-as-heading Best practices (experimental) Paragraph styled to look like a heading

Moderate Rules — fix in near-term backlog

Rule ID Category Description
heading-order Headings Heading levels skipped (e.g., h1 → h3)
empty-heading Headings Heading has no discernible text
th-has-data-cells Tables Table headers have no associated data cells
td-headers-attr Tables Table cells reference invalid header IDs
meta-viewport Meta Viewport user-scalable=no disables zoom
html-xml-lang-mismatch Language lang and xml:lang attributes disagree
form-field-multiple-labels Forms Form field has multiple conflicting labels
landmark-one-main Best practices Page has no <main> landmark
landmark-banner-is-top-level Best practices banner landmark not at top level
landmark-contentinfo-is-top-level Best practices contentinfo landmark not at top level
landmark-main-is-top-level Best practices main landmark not at top level
landmark-no-duplicate-banner Best practices More than one banner landmark
landmark-no-duplicate-contentinfo Best practices More than one contentinfo landmark
landmark-no-duplicate-main Best practices More than one main landmark
region Best practices Content exists outside landmark regions
page-has-heading-one Best practices Page has no <h1>
scope-attr-valid Best practices scope attribute has invalid value
accesskeys Best practices accesskey values are not unique

Minor Rules

Rule ID Category Description
table-duplicate-name Tables <caption> text duplicates summary attribute
aria-deprecated-role ARIA Deprecated ARIA role used
server-side-image-map Keyboard Server-side image map used
aria-text ARIA (best practice) role="text" on an element with focusable descendants

Disabled-by-default rules (deprecated marquee/blink/audio-caption) are not listed above — flag them if encountered, but they are not enabled in a default scan.

The three WCAG AAA rules axe-core disables by default report against a level the project's AA target does not require. If enabled and a project has not declared a broader target, classify a confirmed finding from one of these rules as obligation: aspirational, not advisory — it is still a real AAA-level finding, just not part of the AA baseline. Do not report satisfying one of these rules as WCAG AAA conformance.


Running axe-core in CI (Playwright)

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

test('No WCAG 2.x AA violations', async ({ page }) => {
  await page.goto('/');
  const results = await new AxeBuilder({ page })
    .withTags(['wcag2a', 'wcag2aa', 'wcag21aa', 'wcag22aa'])
    .analyze();
  expect(results.violations).toEqual([]);
});

Common configuration options:

// Exclude a specific element (use sparingly — document the reason)
.exclude('#known-false-positive')

// Include only a specific element
.include('#component-under-test')

// Disable a specific rule (document the reason and JIRA/issue link)
.disableRules(['color-contrast'])

Definition of Done Checklist

  • axe-core scans run on every PR with wcag2a, wcag2aa, wcag21aa, wcag22aa tags
  • Zero critical violations in production code
  • Zero serious violations in production code (or explicit waiver with issue link)
  • All rule exclusions documented with reason and associated issue
  • Light and dark colour schemes both tested
  • Mobile viewport tested
  • axe results published as CI artifact for reference

Key WCAG Criteria (automation coverage)

  • 1.1.1 Non-text Content (A)
  • 1.3.1 Info and Relationships (A)
  • 1.4.3 Contrast Minimum (AA)
  • 2.4.2 Page Titled (A)
  • 3.1.1 Language of Page (A)
  • 4.1.2 Name, Role, Value (A)
  • 4.1.3 Status Messages (AA) — partial coverage

Automation covers ~30–40% of WCAG issues. Always pair with manual testing.


References

Standards horizon: These rules target WCAG 2.2 AA. Monitor: https://www.w3.org/TR/wcag-3.0/