Accessibility Guides for deafblind
Learn how to identify and fix common accessibility issues flagged by Axe Core — so your pages are inclusive and usable for everyone. Also check our HTML Validation Guides.
An image map is an <img> element linked to a <map> element via the usemap attribute. Inside the <map>, individual <area> elements define clickable hotspots that function as links. Each of these <area> elements is essentially a link, and like all links, it must have an accessible name that describes its purpose.
Why This Is an Accessibility Problem
Screen readers cannot interpret graphical content. When a user navigates to a clickable <area> that lacks alternative text, the screen reader has no meaningful label to announce. In many cases, it will fall back to reading the link URL or the image filename — neither of which conveys the purpose of the link. This critically impacts:
- Blind users and deafblind users who rely entirely on screen readers to navigate and interact with content.
- Users with mobility impairments who use assistive technologies like switch devices or voice control, which depend on accessible names to identify interactive elements.
This rule relates to the following WCAG success criteria:
-
WCAG 2.4.4 – Link Purpose (In Context) (Level A): The purpose of each link must be determinable from the link text alone, or from the link text combined with its programmatically determined context. An
<area>without alternative text has no discernible purpose. -
WCAG 4.1.2 – Name, Role, Value (Level A): All user interface components must have a programmatically determined name. An
<area>element is an interactive component, so it requires an accessible name.
This rule also applies under Section 508, EN 301 549, and Trusted Tester requirements.
How to Fix It
Ensure every active <area> element inside a <map> has an accessible name by using one of these methods:
-
altattribute (preferred) — Add descriptivealttext directly to the<area>element. -
aria-labelattribute — Provide a text label viaaria-label. -
aria-labelledbyattribute — Reference another element that contains the label text.
The alt text should clearly describe the purpose or destination of the link, not the visual appearance of the hotspot region.
Also, make sure the parent <img> element has its own alt attribute describing the image as a whole.
Examples
Incorrect: <area> Elements Without Alternative Text
In this example, the <area> elements have no alt text. Screen readers cannot communicate what each clickable region does.
<img src="solar_system.jpg" alt="Solar System" width="472" height="800" usemap="#solar-map">
<map name="solar-map">
<area shape="rect" coords="115,158,276,192" href="https://example.com/mercury">
<area shape="rect" coords="115,193,276,234" href="https://example.com/venus">
<area shape="rect" coords="115,235,276,280" href="https://example.com/earth">
</map>
Correct: <area> Elements With alt Text
Each <area> now has a descriptive alt attribute that communicates the link’s purpose.
<img src="solar_system.jpg" alt="Solar System" width="472" height="800" usemap="#solar-map">
<map name="solar-map">
<area shape="rect" coords="115,158,276,192" href="https://example.com/mercury" alt="Mercury">
<area shape="rect" coords="115,193,276,234" href="https://example.com/venus" alt="Venus">
<area shape="rect" coords="115,235,276,280" href="https://example.com/earth" alt="Earth">
</map>
Correct: Using aria-label Instead of alt
<img src="floor_plan.png" alt="Office floor plan" width="600" height="400" usemap="#office-map">
<map name="office-map">
<area shape="rect" coords="0,0,200,200" href="/rooms/conference-a" aria-label="Conference Room A">
<area shape="rect" coords="200,0,400,200" href="/rooms/kitchen" aria-label="Kitchen">
</map>
Incorrect: Server-Side Image Map
Server-side image maps use the ismap attribute and rely on mouse click coordinates sent to the server. These are not keyboard accessible and provide no text alternatives for individual regions. Avoid this pattern entirely.
<a href="/maps/nav.map">
<img src="navbar.gif" alt="Navigation" ismap>
</a>
Instead, replace server-side image maps with client-side image maps (usemap and <map>) that include proper alt text on each <area>, or use a different navigational pattern altogether such as a standard list of links.
The WAI-ARIA specification organizes roles, states, and properties into a strict taxonomy. Each role defines three categories of attributes it can use:
- Required attributes — must be present for the role to function correctly.
- Supported attributes — optionally enhance the role’s semantics.
- Inherited attributes — come from superclass roles in the ARIA role hierarchy.
Any ARIA attribute that doesn’t fall into one of these categories is not allowed on that role. This applies equally to explicit roles (set with the role attribute) and implicit roles that HTML elements carry by default. For instance, <button> has an implicit role of button, <input type="checkbox"> has an implicit role of checkbox, and <h2> has an implicit role of heading.
When an unsupported attribute appears on an element, the result is unpredictable. A screen reader might silently ignore it, or it might announce contradictory information — for example, describing a heading as a checkable control. In the worst case, invalid role-attribute combinations can break accessibility for entire sections of a page.
Who is affected
This issue has a critical impact on people who use assistive technologies:
- Screen reader users (blind and deafblind users) depend on accurate role and state information to understand and interact with content. Conflicting ARIA attributes can cause elements to be announced as something they are not.
- Voice control users rely on correctly exposed semantics to issue commands targeting specific controls. Misrepresented roles can make controls unreachable by voice.
- Users of switch devices and alternative input methods depend on tools that interpret ARIA roles and attributes to identify operable controls. Invalid attributes can make controls appear inoperable or misrepresent their purpose entirely.
When ARIA attributes conflict with an element’s role, these users may encounter controls that lie about what they do, states that never update correctly, or entire regions that become completely unusable.
Relevant WCAG success criteria
This rule relates to WCAG 2.0, 2.1, and 2.2 Success Criterion 4.1.2: Name, Role, Value (Level A), as well as EN 301 549 clause 9.4.1.2. This criterion requires that all user interface components expose their name, role, and value to assistive technologies in a way that can be programmatically determined. Using unsupported ARIA attributes on a role violates this criterion because it introduces properties that conflict with the element’s actual role, breaking the contract between the page and assistive technology.
How to fix the problem
-
Identify the element’s role. Check for an explicit
roleattribute. If none is present, determine the element’s implicit ARIA role from its HTML tag. For example,<input type="checkbox">has an implicit role ofcheckbox, and<nav>has an implicit role ofnavigation. -
Look up the allowed attributes for that role in the WAI-ARIA specification’s role definitions. Each role page lists its required states and properties, supported states and properties, and inherited properties from superclass roles.
-
Remove or relocate any ARIA attribute that isn’t in the allowed list. If the attribute belongs on a different element within your component, move it there.
-
Reconsider the role. Sometimes the right fix isn’t removing the attribute but changing the element’s role to one that supports the attribute you need. If you want a toggleable control, use
role="switch"orrole="checkbox"instead ofrole="button". -
Consult the ARIA in HTML specification for additional conformance rules about which ARIA attributes are appropriate on specific HTML elements, including restrictions on how elements can be named.
Examples
Incorrect: unsupported attribute on an explicit role
The aria-checked attribute is not supported on role="textbox" because a textbox is not a checkable control. A screen reader might announce this element as both a text input and a checked control.
<div role="textbox" aria-checked="true" contenteditable="true">
Enter your name
</div>
Correct: unsupported attribute removed
Remove aria-checked since it has no meaning on a textbox. Use aria-label to provide an accessible name.
<div role="textbox" contenteditable="true" aria-label="Your name">
</div>
Incorrect: unsupported attribute on an implicit role
The <h2> element has an implicit role of heading. The aria-selected attribute is not supported on headings because headings are not selectable items.
<h2 aria-selected="true">Account Settings</h2>
Correct: unsupported attribute removed from heading
If selection semantics aren’t needed, remove the attribute. If you need selection behavior, use an element with an appropriate role such as tab.
<h2>Account Settings</h2>
Incorrect: role doesn’t match the intended behavior
The developer wants a toggleable control but used role="button", which does not support aria-checked.
<div role="button" aria-checked="true" tabindex="0">
Dark mode
</div>
Correct: role changed to one that supports the attribute
Changing the role to switch makes aria-checked valid. The element remains keyboard-operable via tabindex="0".
<div role="switch" aria-checked="true" tabindex="0" aria-label="Dark mode">
Dark mode
</div>
Incorrect: unsupported attribute on a native HTML element
The <a> element has an implicit role of link. The aria-required attribute is not supported on links because links are not form fields that accept input.
<a href="/terms" aria-required="true">Terms of Service</a>
Correct: unsupported attribute removed from link
Remove aria-required from the link. If you need to indicate that agreeing to terms is mandatory, communicate that through a form control such as a checkbox.
<a href="/terms">Terms of Service</a>
Correct: supported attribute on a matching implicit role
The aria-expanded attribute is supported on the implicit button role, making this combination valid.
<button aria-expanded="false" aria-controls="menu-list">
Menu
</button>
<ul id="menu-list" hidden>
<li><a href="/home">Home</a></li>
<li><a href="/about">About</a></li>
</ul>
HTML elements come with built-in semantics — a <button> is inherently a button, a <ul> is inherently a list, and so on. When you assign a WAI-ARIA role to an element, you’re overriding those built-in semantics and telling assistive technologies to treat the element differently. However, not all overrides make sense. Some combinations conflict with the element’s native behavior, its expected interaction patterns, or the browser’s internal handling of the element. For example, assigning role="button" to a <ul> element creates a contradiction: the browser still treats it as a list structurally, but screen readers announce it as a button, resulting in confusing and unpredictable behavior.
This issue primarily affects users who rely on screen readers and other assistive technologies. These tools depend on accurate role information to communicate what an element is, how it behaves, and how to interact with it. When role assignments conflict with the underlying HTML element, screen readers may announce the wrong type of control, skip content entirely, or present a user interface that doesn’t match what sighted users see. Users who are blind, deafblind, or who use assistive technologies for mobility impairments are all affected.
While this rule is classified as a Deque best practice rather than a direct WCAG failure, it aligns with the principles behind WCAG 4.1.2 Name, Role, Value, which requires that user interface components expose their role correctly to assistive technologies. Mismatched roles undermine this requirement. At best, an invalid element-role combination has no effect; at worst, it can disable accessibility for entire sections of a page.
How to Fix
-
Check the ARIA in HTML specification. The ARIA in HTML spec defines which
rolevalues are allowed for each HTML element. Before assigning a role, verify that the combination is permitted. -
Use the right element for the job. Often, the best fix is to use a native HTML element that already has the semantics you need, rather than overriding a different element with a
role. For example, use a<button>for button behavior instead of addingrole="button"to a<div>. - Restructure when necessary. If you need a specific role, find an element that is allowed to carry it. This might mean changing your markup structure slightly.
-
Don’t use abstract roles. Roles like
widget,landmark,roletype,structure, andcommandare abstract and must never be used directly in content. They exist only as conceptual categories in the ARIA taxonomy.
Examples
Incorrect: Role not appropriate for the element
A <ul> element assigned role="button" — lists cannot be buttons:
<ul role="button">Name</ul>
A <button> element assigned role="heading" — buttons should not be headings:
<button role="heading" aria-level="2">Welcome</button>
In both cases, the assigned role conflicts with the element’s native semantics and expected behavior, causing assistive technologies to report inaccurate information.
Correct: Role appropriate for the element
A <ul> element assigned role="menu" — this is an allowed role for <ul>, and the child elements use compatible roles:
<ul role="menu">
<li role="none">
<button role="menuitem">Start</button>
</li>
<li role="none">
<button role="menuitem">Stop</button>
</li>
</ul>
Here, role="menu" is a permitted override for <ul>, role="none" removes the <li> list-item semantics (which aren’t meaningful in a menu context), and role="menuitem" is allowed on <button> elements.
Correct: Using native HTML elements instead of role overrides
Rather than forcing mismatched roles, use elements that already have the semantics you need:
<button type="button">Name</button>
<h2>Welcome</h2>
Native HTML elements provide built-in keyboard support, focus management, and correct semantics without any ARIA needed. This is almost always the simplest and most robust approach.
The aria-braillelabel and aria-brailleroledescription attributes were introduced to give authors fine-grained control over how content is presented on refreshable braille displays. For example, a visual “4 stars” rating might be represented as **** in braille to save space and improve readability on a limited-cell display. Similarly, a custom role description like “slide” might be abbreviated to “sld” for braille output.
However, these braille-specific attributes are designed as overrides, not standalone values. They modify how an existing accessible name or role description is rendered in braille. If no accessible name or role description exists, there’s nothing for the braille attribute to override. The WAI-ARIA specification states that braille attributes without their non-braille equivalents should be ignored, but assistive technologies may not handle this consistently. Some screen readers might display the braille-only text while others ignore it entirely, leading to an unpredictable experience.
Who is affected
This issue primarily impacts users who are blind or deafblind and rely on refreshable braille displays. It can also affect users with mobility impairments who use assistive technologies that interpret ARIA attributes. When braille attributes lack their non-braille counterparts, these users may encounter missing labels or confusing role information, making it harder — or impossible — to understand and interact with content.
Related WCAG success criteria
This rule maps to WCAG Success Criterion 4.1.2: Name, Role, Value (Level A), which requires that all user interface components have an accessible name and role that can be programmatically determined. Using aria-braillelabel without a proper accessible name, or aria-brailleroledescription without aria-roledescription, means the element’s name or role description is not reliably communicated to assistive technologies. This applies to WCAG 2.0, 2.1, and 2.2 at Level A, as well as EN 301 549 guideline 9.4.1.2.
How to fix it
-
Add a non-braille equivalent. If an element has
aria-braillelabel, ensure it also has an accessible name — viaaria-label,aria-labelledby, visible text content, or thealtattribute on images. If an element hasaria-brailleroledescription, ensure it also hasaria-roledescription. -
Check attribute placement. The
aria-braillelabeloraria-brailleroledescriptionattribute might be on the wrong element. Verify it’s on the same element that has the corresponding accessible name or role description. - Remove unnecessary braille attributes. If the braille attribute isn’t serving a meaningful purpose (e.g., if the braille text would be the same as the accessible name), remove it entirely.
Examples
Incorrect: aria-braillelabel without an accessible name
The image has an empty alt attribute, so it has no accessible name. The aria-braillelabel has nothing to override.
<img alt="" aria-braillelabel="****" src="stars.jpg">
Correct: aria-braillelabel with an accessible name
The button has an accessible name from the image’s alt text. The aria-braillelabel overrides how that name appears on a braille display.
<button aria-braillelabel="****">
<img alt="4 stars" src="stars.jpg">
</button>
Incorrect: aria-brailleroledescription without aria-roledescription
The element has a braille role description but no aria-roledescription to serve as the non-braille equivalent.
<div
role="article"
aria-labelledby="slideheading"
aria-brailleroledescription="sld">
<h1 id="slideheading">My vacation in Rome</h1>
</div>
Correct: aria-brailleroledescription with aria-roledescription
Both aria-roledescription and aria-brailleroledescription are present, so the braille display can use the abbreviated version while screen readers use the full role description.
<div
role="article"
aria-labelledby="slideheading"
aria-roledescription="slide"
aria-brailleroledescription="sld">
<h1 id="slideheading">My vacation in Rome</h1>
</div>
Incorrect: aria-braillelabel on the wrong element
The aria-braillelabel is on a <span> that has no accessible name, even though the parent button does.
<button aria-label="Close">
<span aria-braillelabel="cls">X</span>
</button>
Correct: aria-braillelabel on the element with the accessible name
The aria-braillelabel is placed on the same element that has aria-label.
<button aria-label="Close" aria-braillelabel="cls">
<span>X</span>
</button>
When ARIA attributes are applied to elements where the specification says they should not be used, the result is unpredictable behavior across browsers and assistive technologies. Different browsers handle these conflicts inconsistently — some ignore the ARIA attribute, others override the native state, and still others pass both values through. This inconsistency means that a screen reader user on one browser may hear a completely different state than a screen reader user on another, creating a confusing and unreliable experience.
This rule relates to WCAG 2.0/2.1/2.2 Success Criterion 4.1.2: Name, Role, Value (Level A), which requires that for all user interface components, the name, role, and states can be programmatically determined. When ARIA attributes conflict with native semantics or are used outside their allowed context, the programmatically determined state becomes ambiguous or incorrect. Users affected include people who are blind or deafblind and rely on screen readers, as well as people with mobility disabilities who use alternative input devices that depend on accurate ARIA information.
There are two main scenarios this rule checks:
The aria-checked Attribute on Native Checkboxes
The aria-checked attribute should not be used on an <input type="checkbox"> element. Native HTML checkboxes already communicate their checked state to the browser’s accessibility tree through the checked property. When you add aria-checked on top of this, you create two competing sources of truth. If the native checked state and the aria-checked value fall out of sync — which is easy to do — some assistive technologies will report the native state while others report the ARIA state. The user has no way to know which is correct.
How to fix it
You have two options:
-
Remove
aria-checkedand rely on the nativecheckedattribute or property. If you need a “mixed” or indeterminate state, set theindeterminateproperty on the checkbox via JavaScript. -
Replace the native checkbox with a custom element (e.g., a
<div>or<span>) that usesrole="checkbox"along witharia-checked. When doing this, you must also ensure the element is keyboard accessible (focusable and togglable with Space) and has an accessible name.
Row-Specific Attributes Outside a treegrid
The attributes aria-posinset, aria-setsize, aria-expanded, and aria-level are only valid on a row (a <tr> element or an element with role="row") when that row is inside a treegrid. These attributes describe hierarchical tree relationships — position within a set, nesting level, and expandability — which are concepts that only make sense in a tree grid context. When used inside a plain <table> or grid, these attributes serve no function and may cause screen readers to announce confusing or nonsensical information.
How to fix it
Either remove the unsupported attributes from the rows, or change the parent container’s role to treegrid if the data truly represents a hierarchical, expandable structure. If you switch to treegrid, make sure cells use role="gridcell" and that the keyboard interaction pattern matches what users expect from a tree grid (arrow key navigation for expanding/collapsing rows).
Examples
Bad example: aria-checked on a native checkbox
The aria-checked attribute conflicts with the native checkbox state.
<label>
<input type="checkbox" aria-checked="true">
I agree to make my website accessible
</label>
Good example: native checkbox without aria-checked
The browser communicates the checked state natively — no ARIA override needed.
<label>
<input type="checkbox" checked>
I agree to make my website accessible
</label>
Good example: custom checkbox using aria-checked
When building a custom checkbox, aria-checked is appropriate because there is no native checked state.
<div role="checkbox" aria-checked="true" tabindex="0" aria-label="I agree to make my website accessible">
✓ I agree to make my website accessible
</div>
Bad example: tree attributes on rows inside a plain table
The aria-level and aria-expanded attributes are not valid on rows inside a <table>.
<table>
<tr aria-level="1" aria-expanded="false">
<td>My Downloads</td>
</tr>
<tr aria-level="2">
<td>Documents</td>
</tr>
</table>
Good example: tree attributes on rows inside a treegrid
Changing the table’s role to treegrid makes these attributes valid and meaningful.
<table role="treegrid">
<tr aria-level="1" aria-expanded="false">
<td role="gridcell">My Downloads</td>
</tr>
<tr aria-level="2" class="hidden">
<td role="gridcell">Documents</td>
</tr>
</table>
Good example: removing unsupported attributes from a plain table
If the data is not hierarchical, simply remove the tree-related attributes.
<table>
<tr>
<td>My Downloads</td>
</tr>
<tr>
<td>Documents</td>
</tr>
</table>
The WAI-ARIA specification evolves over time. As it matures, certain roles are deprecated because they were found to be redundant, poorly supported, or better served by other mechanisms. When you use a deprecated role, you’re relying on semantics that assistive technologies are no longer expected to support. This means the role may be completely ignored, misinterpreted, or cause unexpected behavior.
Users most affected include:
- Blind and deafblind users who rely on screen readers to convey the purpose and structure of elements on a page.
- Users with mobility impairments who depend on assistive technologies that use ARIA roles for navigation and interaction.
When a screen reader encounters an element with a deprecated role, it may announce it generically (e.g., as a simple group or section) or skip the role announcement entirely. This strips away meaningful context that helps users understand the content structure and interact with it effectively.
Relevant WCAG Success Criteria
This rule relates to WCAG Success Criterion 4.1.2: Name, Role, Value (Level A). This criterion requires that for all user interface components, the name, role, and value can be programmatically determined and that changes to these are available to assistive technologies. Using a deprecated role means the role cannot be reliably determined, which violates this requirement.
This applies across WCAG 2.0, 2.1, and 2.2 at Level A, as well as EN 301 549 (guideline 9.4.1.2).
How to Fix It
-
Identify deprecated roles in your codebase. The axe-core rule checks all elements with a
roleattribute against the current WAI-ARIA specification. -
Replace deprecated roles with supported alternatives. Currently, the primary deprecated role flagged is:
-
directory: Replace withlist,tree, orsectiondepending on the content structure. If the directory represents a flat list of items (like a table of contents), uselist. If it represents a hierarchical, expandable structure, usetree. If it’s a general grouping of related content, usesection.
-
- Test with assistive technologies after making changes to confirm the new role conveys the intended meaning.
As the WAI-ARIA specification continues to evolve, additional roles may be deprecated in future versions. Keep your ARIA usage up to date by referencing the latest WAI-ARIA specification.
Examples
Incorrect: Using the Deprecated directory Role
<div role="directory">
<ul>
<li><a href="#section-1">Section 1</a></li>
<li><a href="#section-2">Section 2</a></li>
<li><a href="#section-3">Section 3</a></li>
</ul>
</div>
The directory role is deprecated. Assistive technologies may not recognize it, leaving users without useful semantic information about this element.
Correct: Using a Supported Role Instead
If the content is a simple list of links (such as a table of contents), use list or rely on the native <ul> semantics:
<nav aria-label="Table of contents">
<ul>
<li><a href="#section-1">Section 1</a></li>
<li><a href="#section-2">Section 2</a></li>
<li><a href="#section-3">Section 3</a></li>
</ul>
</nav>
In this example, the native <ul> element already provides the list role, and wrapping it in a <nav> with an aria-label gives assistive technology users clear context about its purpose.
Correct: Using tree for Hierarchical Content
If the content represents an expandable, nested structure, use the tree role with appropriate child roles:
<ul role="tree" aria-label="Site map">
<li role="treeitem" aria-expanded="true">
Section 1
<ul role="group">
<li role="treeitem">Subsection 1.1</li>
<li role="treeitem">Subsection 1.2</li>
</ul>
</li>
<li role="treeitem">Section 2</li>
</ul>
Correct: Using section for a General Content Grouping
If the deprecated directory role was used simply to group related content, a <section> element with an accessible name is a good replacement:
<section aria-label="Staff directory">
<ul>
<li>Alex Johnson — Engineering</li>
<li>Maria Garcia — Design</li>
<li>Sam Lee — Marketing</li>
</ul>
</section>
The key is to choose a replacement that accurately reflects the structure and purpose of the content, ensuring assistive technologies can convey it meaningfully to users.
The aria-hidden="true" attribute tells assistive technologies to ignore an element and all of its descendants. This is useful for hiding purely decorative content — such as icon fonts or redundant visuals — that would clutter the screen reader experience. However, a serious problem arises when focusable elements like links, buttons, form inputs, or elements with tabindex="0" exist inside an aria-hidden="true" container.
When this happens, keyboard users can still Tab to those elements, but screen readers won’t announce them. The user lands on what feels like an invisible, unlabeled control. They have no way to know what the element is or what it does. This affects blind users, deafblind users, users with low vision who rely on screen readers, and mobility-impaired users who navigate exclusively by keyboard.
It’s also important to understand that aria-hidden="false" on a descendant does not override aria-hidden="true" on an ancestor. Once a parent is hidden from the accessibility tree, all children remain hidden regardless of their own aria-hidden value. Any focusable children inside that subtree still create the same problem.
Related WCAG Success Criteria
This rule primarily relates to WCAG Success Criterion 4.1.2: Name, Role, Value (Level A). This criterion requires that for all user interface components, the name and role can be programmatically determined, and states, properties, and values can be programmatically set. A focusable element inside an aria-hidden="true" container violates this because its name and role are stripped from the accessibility API while it remains reachable via keyboard — making it impossible for assistive technologies to convey its purpose. This rule is flagged across WCAG 2.0, 2.1, and 2.2 at Level A, as well as in Trusted Tester, EN 301 549, and RGAA guidelines.
How to Fix It
There are several strategies to resolve this issue:
-
Remove
aria-hidden="true"from elements that contain focusable children, if those children need to be interactive. -
Remove focusable elements from inside the
aria-hidden="true"container if the entire section is truly meant to be hidden. -
Make focusable elements unfocusable by adding
tabindex="-1"to links, buttons, or other interactive elements inside the hidden container. -
Use the
disabledattribute on form controls (notaria-disabled, which does not actually prevent focus). -
Hide elements with CSS using
display: noneorvisibility: hidden, which removes them from both the accessibility tree and the focus order simultaneously.
If you need to hide content from assistive technologies, ensure equivalent meaning and functionality is still available through other accessible means.
Examples
Incorrect: Focusable link inside aria-hidden="true"
The link is removed from the accessibility tree but still receives keyboard focus.
<div aria-hidden="true">
<a href="/home">Home</a>
</div>
Incorrect: Offscreen focusable link inside aria-hidden="true"
Moving a link offscreen does not remove it from the focus order.
<div aria-hidden="true">
<a href="/" style="position:absolute; top:-999em">Link</a>
</div>
Incorrect: Using aria-disabled instead of disabled
The aria-disabled attribute does not actually prevent the input from receiving focus.
<div aria-hidden="true">
<input aria-disabled="true" />
</div>
Incorrect: Element with tabindex="0" and aria-hidden="true"
Adding tabindex="0" makes a normally non-focusable element focusable, creating a conflict with aria-hidden="true".
<p tabindex="0" aria-hidden="true">Some descriptive text</p>
Incorrect: Trying to override aria-hidden on a descendant
Setting aria-hidden="false" on a child does not re-expose it when a parent has aria-hidden="true". The button remains hidden from assistive technologies but still receives focus.
<div aria-hidden="true">
<div aria-hidden="false">
<button>Submit</button>
</div>
</div>
Incorrect: Focusable <summary> inside aria-hidden="true"
The <summary> element is natively focusable.
<details aria-hidden="true">
<summary>More info</summary>
<p>Additional details here.</p>
</details>
Correct: Non-focusable content inside aria-hidden="true"
A paragraph with no interactive elements is safe to hide.
<p aria-hidden="true">Decorative description text</p>
Correct: Focusable elements hidden with CSS display: none
Using display: none removes the link from both the focus order and the accessibility tree.
<div aria-hidden="true">
<a href="/" style="display:none">Link</a>
</div>
Correct: Focusable elements made unfocusable with tabindex="-1"
Adding tabindex="-1" removes the button from the tab order.
<div aria-hidden="true">
<button tabindex="-1">Close</button>
</div>
Correct: Form input properly disabled with the disabled attribute
The disabled attribute prevents the input from receiving focus entirely.
<input disabled aria-hidden="true" />
Correct: Removing aria-hidden and keeping elements interactive
If the content needs to be focusable, simply don’t hide it from assistive technologies.
<div>
<a href="/home">Home</a>
</div>
When you use ARIA roles to create custom input controls instead of native HTML elements, the browser no longer automatically associates a label with the control. Native <input>, <select>, and <textarea> elements support the <label> element through implicit wrapping or explicit for/id pairing, but custom <div> or <span> elements with ARIA roles do not. This means you must supply an accessible name through ARIA-specific mechanisms.
This rule applies to elements with any of the following ARIA input roles:
-
combobox -
listbox -
searchbox -
slider -
spinbutton -
textbox
Who is affected
Without an accessible name, users who rely on screen readers (including blind and deafblind users) hear only the role of the element — for example, “textbox” — with no indication of what information to enter. Users with mobility impairments who navigate via voice control also depend on accessible names to target specific controls by speaking their labels. This creates a serious barrier to interaction.
Related WCAG success criteria
This rule maps to WCAG 2.0, 2.1, and 2.2 Success Criterion 4.1.2: Name, Role, Value (Level A). This criterion requires that all user interface components have a name that can be programmatically determined by assistive technologies. It is a Level A requirement, meaning it represents the minimum baseline of accessibility.
How to fix the problem
Because <label> elements do not work reliably with non-native elements like <div> or <span>, you need to use one of these approaches:
-
aria-label— Add a concise, descriptive label directly on the element. -
aria-labelledby— Point to theidof one or more visible elements that serve as the label. -
title— Use thetitleattribute as a last resort (it is less discoverable for sighted users).
Make sure the accessible name you provide is not empty or whitespace-only, and that any id referenced by aria-labelledby actually exists in the DOM.
Common mistakes
-
Setting
aria-labelto an empty or whitespace-only string (e.g.,aria-label=" "). -
Using
aria-labelledbywith anidthat doesn’t exist on the page. -
Wrapping a custom ARIA widget in a
<label>element, which does not provide a programmatic name for non-native elements in most browser/screen reader combinations. -
Using
<label for="id">to point to a<div>— theforattribute only works with native labelable elements like<input>,<select>, and<textarea>.
Examples
Incorrect: no accessible name on a combobox
The <div> has a combobox role but no label of any kind.
<div role="combobox">England</div>
Incorrect: aria-label is only whitespace
An empty or whitespace-only aria-label does not count as an accessible name.
<div aria-label=" " role="combobox">England</div>
Incorrect: aria-labelledby references a non-existent id
The referenced id must exist in the document; otherwise the accessible name resolves to empty.
<div role="listbox" aria-labelledby="color-label">
<div role="option">Orange</div>
</div>
<!-- No element with id="color-label" exists -->
Incorrect: <label> wrapping a non-native element
Implicit label association does not work for <div> elements with ARIA roles.
<label>
First name
<div role="textbox"></div>
</label>
Incorrect: explicit <label for> targeting a non-native element
The for attribute only creates a programmatic association with native labelable elements.
<label for="name-field">First name</label>
<div role="textbox" id="name-field"></div>
Correct: aria-label on a combobox
<div role="combobox" aria-label="Country">England</div>
Correct: aria-labelledby pointing to a visible label
<p id="color-label">Select a color:</p>
<div role="listbox" aria-labelledby="color-label">
<div role="option">Orange</div>
</div>
Correct: aria-labelledby on a searchbox
<p id="search-label">Search currency pairs:</p>
<div role="searchbox"
contenteditable="true"
aria-labelledby="search-label"></div>
Correct: aria-label on a slider
<div role="slider"
aria-label="Choose a value"
aria-valuemin="1"
aria-valuemax="7"
aria-valuenow="2"
tabindex="0"></div>
Correct: aria-label on a spinbutton
<div role="spinbutton"
aria-label="Enter quantity"
aria-valuemin="0"
aria-valuemax="10"
aria-valuenow="8"
tabindex="0"></div>
Correct: aria-labelledby on a textbox
<p id="name-label">First name</p>
<div role="textbox"
contenteditable="true"
aria-labelledby="name-label"></div>
When possible, prefer native HTML form controls (<input>, <select>, <textarea>) because they have built-in label support and keyboard behavior. Use custom ARIA input roles only when native elements cannot meet your design requirements, and always ensure those custom controls have an accessible name.
The WAI-ARIA specification defines which attributes are permitted, required, or prohibited for each role. When you use a prohibited attribute on a role, you’re relying on a combination that assistive technologies are not designed to support. The result is that the information you intended to communicate — such as a label or description — may be silently dropped.
This creates a serious problem for users who depend on assistive technologies, including people who are blind, deafblind, or have mobility impairments. Screen readers might ignore the prohibited attribute, leaving the user without context. Some assistive technologies may attempt to compensate, leading to inconsistent or confusing behavior across different tools and browsers.
A common example is using aria-label on an element with role="presentation" or role="none". These roles explicitly tell assistive technologies to ignore the element’s semantics, so labeling it with aria-label is contradictory. Similarly, text-level semantic roles like code, insertion, deletion, strong, emphasis, subscript, superscript, and paragraph prohibit aria-label and aria-labelledby because these roles represent inline text content that should not carry an accessible name separate from their text content.
Related WCAG success criteria
This rule relates to WCAG Success Criterion 4.1.2: Name, Role, Value (Level A), which requires that for all user interface components, the name, role, and states/properties can be programmatically determined. Using prohibited ARIA attributes violates this criterion because the intended name or state information cannot be reliably communicated to assistive technologies.
How to fix it
When axe flags a prohibited ARIA attribute, consider these approaches:
- Remove the prohibited attribute — If the information it conveys is not essential, simply remove it.
-
Change the element’s role — Switch to a role that permits the attribute you need. For instance, if you need
aria-label, don’t userole="none". - Provide the information as visible text — Instead of relying on the prohibited attribute, include the information directly in the page content where all users can access it.
- Move the attribute to a different element — Place the attribute on a parent or child element that has a role supporting it.
Examples
Incorrect: aria-label on an element with role="presentation"
The presentation role tells assistive technologies to ignore the element. Adding aria-label contradicts this and will be ignored.
<div role="presentation" aria-label="Navigation section">
<a href="/home">Home</a>
<a href="/about">About</a>
</div>
Correct: Use a role that supports aria-label
If the element needs an accessible name, use a role that permits labeling, such as navigation.
<nav aria-label="Navigation section">
<a href="/home">Home</a>
<a href="/about">About</a>
</nav>
Incorrect: aria-label on a text-level semantic role
Roles like code, strong, emphasis, insertion, and deletion prohibit aria-label and aria-labelledby.
<span role="code" aria-label="JavaScript variable declaration">
const x = 10;
</span>
Correct: Use visible text instead
Provide context through surrounding text content rather than a prohibited attribute.
<p>
The following JavaScript variable declaration
<code>const x = 10;</code>
assigns the value 10 to x.
</p>
Incorrect: aria-labelledby on role="none"
<h2 id="section-title">Features</h2>
<table role="none" aria-labelledby="section-title">
<tr>
<td>Fast</td>
<td>Reliable</td>
</tr>
</table>
Correct: Remove the conflicting role or the prohibited attribute
If the table needs to be labeled, remove role="none" so it retains its native table semantics.
<h2 id="section-title">Features</h2>
<table aria-labelledby="section-title">
<tr>
<td>Fast</td>
<td>Reliable</td>
</tr>
</table>
If the table is truly presentational and doesn’t need a label, remove the aria-labelledby attribute instead.
<table role="none">
<tr>
<td>Fast</td>
<td>Reliable</td>
</tr>
</table>
Why This Is an Accessibility Problem
ARIA roles describe what an element is and how it behaves. Many roles depend on specific state or property attributes to convey critical information about the element. For example, a checkbox role requires aria-checked so users know whether the checkbox is selected. Without it, a screen reader user hears “checkbox” but has no idea whether it’s checked or unchecked.
This issue affects users who are blind, deafblind, or have mobility impairments and rely on assistive technologies to interact with web content. When required attributes are missing, these users lose essential context about the state of interactive widgets.
This rule relates to WCAG 2.0, 2.1, and 2.2 Success Criterion 4.1.2: Name, Role, Value (Level A), which requires that for all user interface components, the name, role, and states can be programmatically determined. Missing required ARIA attributes directly violate this criterion because the element’s state cannot be communicated to assistive technologies.
How Required Attributes Work
Each ARIA role has a set of required states and properties defined in the WAI-ARIA specification. These attributes are essential for the role to function correctly. Some common examples:
| Role | Required Attribute(s) |
|---|---|
checkbox |
aria-checked |
combobox |
aria-expanded, aria-controls |
slider |
aria-valuenow, aria-valuemin, aria-valuemax (note: aria-valuemin and aria-valuemax have implicit defaults of 0 and 100) |
option |
aria-selected |
scrollbar |
aria-controls, aria-valuenow |
separator (focusable) |
aria-valuenow |
meter |
aria-valuenow |
heading |
aria-level |
Some roles inherit requirements from ancestor roles. When a role inherits from multiple ancestors and one ancestor marks a property as supported while another marks it as required, the property becomes required on the inheriting role.
In some cases, default values defined in the specification satisfy the requirement automatically, so you may not always need to explicitly set every attribute. However, explicitly providing required attributes is the safest approach.
How to Fix the Problem
-
Identify the ARIA
roleon the element. - Look up the role in the WAI-ARIA Roles documentation to find its required states and properties.
- Add any missing required attributes with appropriate values.
-
Ensure the attribute values are updated dynamically as the widget state changes (e.g., toggling
aria-checkedbetweentrueandfalsewhen a checkbox is clicked).
Alternatively, consider whether a native HTML element could replace the custom ARIA widget. Native elements like <input type="checkbox">, <input type="range">, and <select> handle state management automatically without needing ARIA attributes.
Examples
Incorrect: Checkbox missing aria-checked
<div role="checkbox" tabindex="0">
Accept terms and conditions
</div>
A screen reader announces this as a checkbox, but the user has no way to know if it is checked or unchecked.
Correct: Checkbox with aria-checked
<div role="checkbox" tabindex="0" aria-checked="false">
Accept terms and conditions
</div>
Better: Use a native HTML checkbox
<label>
<input type="checkbox">
Accept terms and conditions
</label>
Incorrect: Slider missing required value attributes
<div role="slider" tabindex="0">
Volume
</div>
Without aria-valuenow, assistive technologies cannot report the current value of the slider.
Correct: Slider with required attributes
<div role="slider" tabindex="0"
aria-valuenow="50"
aria-valuemin="0"
aria-valuemax="100"
aria-label="Volume">
</div>
Incorrect: Combobox missing aria-expanded and aria-controls
<input role="combobox" type="text" aria-label="Search">
Correct: Combobox with required attributes
<input role="combobox" type="text"
aria-label="Search"
aria-expanded="false"
aria-controls="search-listbox">
<ul id="search-listbox" role="listbox" hidden>
<li role="option">Option 1</li>
<li role="option">Option 2</li>
</ul>
Incorrect: Heading missing aria-level
<div role="heading">Section Title</div>
Correct: Heading with aria-level
<div role="heading" aria-level="2">Section Title</div>
Better: Use a native heading element
<h2>Section Title</h2>
The WAI-ARIA specification defines a strict hierarchy for many roles, where parent and child relationships must be maintained for the accessibility semantics to work as intended. For example, an element with role="list" must contain elements with role="listitem", just as a role="menu" must contain role="menuitem" (or related menu item roles). When these required child roles are absent, assistive technologies like screen readers cannot properly convey the structure of the component. A screen reader user navigating a tree view, for instance, needs to understand the parent container, individual items, and sibling relationships — none of which are communicated correctly if the expected child roles are missing.
This issue critically affects users who are blind, deafblind, or have mobility impairments and rely on assistive technologies to navigate and interact with complex widgets. Without the correct role hierarchy, these users may not understand what type of content they’re interacting with, how many items exist, or how to navigate between them.
This rule relates to WCAG 2.0/2.1/2.2 Success Criterion 1.3.1: Info and Relationships (Level A), which requires that information, structure, and relationships conveyed through presentation can be programmatically determined. When ARIA roles lack their required children, the structural relationships are broken and cannot be programmatically determined by assistive technologies.
There are two ways the required parent-child relationship can be established:
- DOM structure: The child elements with the required roles are direct descendants (or appropriate descendants) of the parent element in the DOM.
-
aria-owns: When the DOM hierarchy doesn’t match the intended accessibility tree structure, thearia-ownsattribute can be used on the parent to explicitly associate child elements that exist elsewhere in the DOM.
How to Fix
- Identify the ARIA role on the parent element.
- Consult the WAI-ARIA specification to determine which child roles are required for that parent role.
-
Ensure all direct children (or owned children via
aria-owns) have the correct required roles. - If you cannot add the required child roles, consider whether the parent role is appropriate for your use case, or use native HTML elements that provide these semantics automatically.
Common Parent-Child Role Requirements
| Parent Role | Required Child Role(s) |
|---|---|
list |
listitem |
menu |
menuitem, menuitemcheckbox, or menuitemradio |
menubar |
menuitem, menuitemcheckbox, or menuitemradio |
tablist |
tab |
tree |
treeitem or group |
grid |
row or rowgroup |
table |
row or rowgroup |
row |
cell, columnheader, gridcell, or rowheader |
feed |
article |
Examples
Incorrect: Missing required child roles
This tablist has children that lack the required tab role:
<div role="tablist">
<div>Tab 1</div>
<div>Tab 2</div>
<div>Tab 3</div>
</div>
This list contains <div> elements without the listitem role:
<div role="list">
<div>Apple</div>
<div>Banana</div>
<div>Cherry</div>
</div>
This menu has children with incorrect roles:
<div role="menu">
<div role="option">Cut</div>
<div role="option">Copy</div>
<div role="option">Paste</div>
</div>
Correct: Required child roles present
The tablist now contains children with role="tab":
<div role="tablist">
<div role="tab" aria-selected="true">Tab 1</div>
<div role="tab">Tab 2</div>
<div role="tab">Tab 3</div>
</div>
The list contains children with role="listitem":
<div role="list">
<div role="listitem">Apple</div>
<div role="listitem">Banana</div>
<div role="listitem">Cherry</div>
</div>
The menu contains children with role="menuitem":
<div role="menu">
<div role="menuitem">Cut</div>
<div role="menuitem">Copy</div>
<div role="menuitem">Paste</div>
</div>
Correct: Using aria-owns for children outside the DOM hierarchy
When required children are not direct descendants in the DOM, use aria-owns to establish the relationship:
<div role="tablist" aria-owns="tab1 tab2 tab3">
<!-- Tabs may be rendered elsewhere in the DOM -->
</div>
<div role="tab" id="tab1" aria-selected="true">Tab 1</div>
<div role="tab" id="tab2">Tab 2</div>
<div role="tab" id="tab3">Tab 3</div>
Correct: Using native HTML elements instead
Native HTML elements automatically provide the correct role relationships without any ARIA attributes:
<ul>
<li>Apple</li>
<li>Banana</li>
<li>Cherry</li>
</ul>
Whenever possible, prefer native HTML elements over ARIA roles. Native elements come with built-in semantics, keyboard behavior, and accessibility support that don’t require manual role management.
The WAI-ARIA specification defines a strict hierarchy for many roles. Some roles are only meaningful when they appear as children of particular parent roles. For example, a tab must be owned by a tablist, a listitem must be owned by a list or group, and a menuitem must be owned by a menu or menubar. When these parent-child relationships are missing, the role becomes semantically orphaned — assistive technologies like screen readers cannot communicate the element’s context, position, or purpose to the user.
Why This Matters
This rule relates to WCAG 2.0/2.1/2.2 Success Criterion 1.3.1: Info and Relationships (Level A), which requires that information, structure, and relationships conveyed visually are also available programmatically. When an ARIA role lacks its required parent, the structural relationship is lost in the accessibility tree.
Users most affected include:
- Blind and deafblind users who rely on screen readers. Without the correct parent role, screen readers cannot announce context such as “item 3 of 5 in a list” or “tab 2 of 4.”
- Users with mobility impairments who depend on assistive technology for navigation. Missing parent roles can break expected keyboard interaction patterns for composite widgets like menus, tablists, and trees.
The user impact is critical — an orphaned role can make an entire widget unusable for assistive technology users.
Common Required Parent Roles
Here are some frequently used roles and their required parents:
| Child Role | Required Parent Role(s) |
|---|---|
listitem |
list or group |
tab |
tablist |
tabpanel |
(associated via tablist pattern) |
menuitem, menuitemcheckbox, menuitemradio |
menu, menubar, or group |
treeitem |
tree or group |
row |
table, grid, rowgroup, or treegrid |
cell, gridcell |
row |
columnheader, rowheader |
row |
option |
listbox or group |
How to Fix the Problem
-
Wrap the element in its required parent role. The simplest fix is to ensure the DOM structure reflects the required hierarchy. Place the element inside a container that has the correct parent role.
-
Use
aria-ownswhen DOM structure doesn’t match. If the child element cannot be a DOM descendant of the parent (e.g., due to layout constraints), you can usearia-ownson the parent element to establish the relationship programmatically. Thearia-ownsattribute tells assistive technologies that the referenced element should be treated as a child, regardless of DOM position. -
Check the WAI-ARIA specification for the specific role you’re using to confirm which parent roles are required.
Examples
Incorrect: listitem Without a list Parent
The listitem role requires a parent with role="list" or role="group", but here it sits directly inside a plain div:
<div>
<div role="listitem">Apples</div>
<div role="listitem">Bananas</div>
<div role="listitem">Cherries</div>
</div>
Correct: listitem Inside a list Parent
<div role="list">
<div role="listitem">Apples</div>
<div role="listitem">Bananas</div>
<div role="listitem">Cherries</div>
</div>
Incorrect: tab Without a tablist Parent
<div>
<button role="tab" aria-selected="true">Tab 1</button>
<button role="tab" aria-selected="false">Tab 2</button>
</div>
Correct: tab Inside a tablist Parent
<div role="tablist">
<button role="tab" aria-selected="true">Tab 1</button>
<button role="tab" aria-selected="false">Tab 2</button>
</div>
Correct: Using aria-owns When DOM Structure Differs
When layout constraints prevent nesting the child inside the parent in the DOM, use aria-owns to establish the relationship:
<div role="tablist" aria-owns="tab1 tab2">
<!-- Tabs are elsewhere in the DOM due to layout needs -->
</div>
<div id="tab1" role="tab" aria-selected="true">Tab 1</div>
<div id="tab2" role="tab" aria-selected="false">Tab 2</div>
Incorrect: menuitem Outside a menu
<div>
<button role="menuitem">Cut</button>
<button role="menuitem">Copy</button>
<button role="menuitem">Paste</button>
</div>
Correct: menuitem Inside a menu
<div role="menu">
<button role="menuitem">Cut</button>
<button role="menuitem">Copy</button>
<button role="menuitem">Paste</button>
</div>
Why This Matters
The aria-roledescription attribute lets authors provide a human-readable, localized description of an element’s role. For example, you might use it to describe a role="slider" as “priority picker” so a screen reader announces something more meaningful to the user. However, this attribute only works when the element already has a role that assistive technologies can identify.
When aria-roledescription is placed on an element with no semantic role — like a plain <div>, <span>, or <p> — there is no role for the description to refine. This creates a confusing situation where assistive technologies may announce a description with no context, announce nothing at all, or behave unpredictably. In some cases, this can break accessibility for entire sections of an application.
This issue primarily affects blind users, deafblind users, and users with mobility impairments who rely on screen readers or other assistive technologies to understand and navigate page content. When role information is nonsensical or missing, these users lose the ability to understand what a UI element is and how to interact with it.
Related WCAG Success Criteria
This rule relates to WCAG Success Criterion 4.1.2: Name, Role, Value (Level A), which requires that for all user interface components, the name, role, and value can be programmatically determined. When aria-roledescription is applied to an element without a semantic role, the role cannot be properly communicated, violating this criterion.
This applies across WCAG 2.0, 2.1, and 2.2 at Level A, as well as EN 301 549 guideline 9.4.1.2.
How the Rule Works
The axe rule aria-roledescription checks every element that has an aria-roledescription attribute and verifies that the element also has a semantic role. There are three possible outcomes:
-
Fail: The element has no role at all (e.g.,
<div>,<span>,<p>without an explicitroleattribute). These elements have a generic or no implicit role, soaria-roledescriptionhas nothing to describe. -
Pass: The element has a well-supported implicit role (like
<button>,<img>,<nav>) or an explicit role (likerole="combobox"). -
Incomplete (needs review): The element has a role that may not be widely supported by assistive technologies (e.g.,
role="rowgroup"). These need manual testing to verify they work correctly.
How to Fix It
-
Identify elements flagged by the rule — they have
aria-roledescriptionbut no semantic role. -
Decide if the element truly needs
aria-roledescription. In many cases, the solution is simply to remove it. -
If the description is needed, either:
-
Use a semantic HTML element that carries an implicit role (e.g., replace
<div>with<button>). -
Add an explicit
roleattribute to the element so the description has context.
-
Use a semantic HTML element that carries an implicit role (e.g., replace
-
Ensure the
aria-roledescriptionvalue meaningfully refines the role — it should describe a more specific version of what the element is, not contradict it.
Examples
Incorrect: aria-roledescription on elements with no semantic role
These elements have no implicit or explicit role, so aria-roledescription has nothing to describe.
<p aria-roledescription="my paragraph">
This is some text.
</p>
<div aria-roledescription="my container">
Some content here.
</div>
<span aria-roledescription="my label">Name</span>
A <p> has no corresponding ARIA role, and a plain <div> or <span> maps to no role (or the generic generic role). Screen readers cannot use the description meaningfully.
Correct: aria-roledescription on elements with an implicit role
These HTML elements carry built-in semantic roles, so the description refines something real.
<img
aria-roledescription="illustration"
src="diagram.png"
alt="System architecture overview" />
<button aria-roledescription="play control">
Play
</button>
The <img> element has an implicit role of img, and <button> has an implicit role of button. The aria-roledescription values provide more specific descriptions of these roles.
Correct: aria-roledescription on elements with an explicit role
<div
role="combobox"
aria-roledescription="city picker"
aria-expanded="false"
aria-haspopup="listbox">
Select a city
</div>
<div
role="slider"
aria-roledescription="priority selector"
aria-valuenow="3"
aria-valuemin="1"
aria-valuemax="5"
tabindex="0">
</div>
The explicit role attribute provides the semantic foundation, and aria-roledescription adds a more user-friendly label for what that role represents in this specific context.
Incorrect fix: Adding a mismatched role just to satisfy the rule
Don’t add a role that doesn’t match the element’s actual behavior just to pass the check.
<!-- Don't do this -->
<p role="button" aria-roledescription="my paragraph">
This is some text.
</p>
If the element is just a paragraph of text, remove aria-roledescription entirely rather than adding an incorrect role.
Needs review: aria-roledescription on elements with limited role support
Some roles have inconsistent assistive technology support. These will be flagged as needing manual review.
<h1 aria-roledescription="page title">Welcome</h1>
<div role="rowgroup" aria-roledescription="data section">
<!-- row content -->
</div>
The heading role and rowgroup role may not consistently support aria-roledescription across all screen readers. Test these cases manually with actual assistive technologies to confirm the description is announced correctly.
When you assign a role attribute to an HTML element, you are explicitly telling browsers and assistive technologies what that element represents and how users should interact with it. If the value is misspelled, invented, or references an abstract role (like widget, roletype, landmark, or structure), the browser cannot map the element to any known role. The result is that assistive technologies either ignore the role entirely or fall back to the element’s native semantics, which may not reflect your intent.
This is a critical accessibility problem. Users who rely on screen readers — including people who are blind, deafblind, or have mobility impairments — depend on accurate role information to navigate and interact with a page. A button announced as a generic element, or a navigation landmark that isn’t recognized at all, can make an interface confusing or completely unusable.
This rule relates to WCAG Success Criterion 4.1.2: Name, Role, Value (Level A), which requires that the role of every user interface component can be programmatically determined. It applies across WCAG 2.0, 2.1, and 2.2, as well as EN 301 549 (Section 9.4.1.2).
How to Fix
-
Check spelling. The most common cause of invalid roles is a simple typo, such as
role="buton"instead ofrole="button". - Use only defined roles. Every value must correspond to an actual role in the WAI-ARIA specification.
-
Never use abstract roles. Abstract roles like
widget,roletype,landmark,structure,input,range,section,sectionhead,select,command, andcompositeexist only as conceptual categories in the spec. They must not be used in markup. -
Consider whether you need
roleat all. Native HTML elements like<button>,<nav>, and<table>already carry implicit roles. Use native elements whenever possible instead of addingroleattributes to generic<div>or<span>elements.
Valid Roles by Category
Here is a summary of valid, non-abstract ARIA roles you can use:
-
Document structure:
application,article,blockquote,caption,code,definition,deletion,document,emphasis,feed,figure,generic,group,heading,img,insertion,list,listitem,mark,math,meter,none,note,paragraph,presentation,separator(when not focusable),strong,subscript,superscript,term,time,toolbar,tooltip -
Landmark:
banner,complementary,contentinfo,form,main,navigation,region,search -
Live region:
alert,log,marquee,status,timer -
Widget:
button,checkbox,gridcell,link,menuitem,menuitemcheckbox,menuitemradio,option,progressbar,radio,scrollbar,searchbox,separator(when focusable),slider,spinbutton,switch,tab,tabpanel,textbox,treeitem -
Composite widget:
combobox,grid,listbox,menu,menubar,radiogroup,tablist,tree,treegrid -
Table:
cell,columnheader,row,rowgroup,rowheader,table -
Window:
alertdialog,dialog
Examples
Incorrect: Misspelled Role
A typo in the role value means assistive technologies won’t recognize it.
<div role="nagivation">
<a href="/">Home</a>
<a href="/about">About</a>
</div>
Incorrect: Made-Up Role
Using a value that doesn’t exist in the ARIA specification.
<div role="footer-container">
<p>© 2024 Example Corp</p>
</div>
Incorrect: Abstract Role
Abstract roles are not allowed in markup.
<div role="widget">
<button>Save</button>
</div>
Correct: Valid ARIA Role
<div role="navigation" aria-label="Main">
<a href="/">Home</a>
<a href="/about">About</a>
</div>
Correct: Using Native HTML Instead of a Role
When a native element already carries the semantics you need, prefer it over a role attribute.
<nav aria-label="Main">
<a href="/">Home</a>
<a href="/about">About</a>
</nav>
Correct: Valid Widget Role
<div role="tablist" aria-label="Settings">
<button role="tab" aria-selected="true" aria-controls="panel-1">General</button>
<button role="tab" aria-selected="false" aria-controls="panel-2">Advanced</button>
</div>
<div role="tabpanel" id="panel-1">General settings content</div>
<div role="tabpanel" id="panel-2" hidden>Advanced settings content</div>
Toggle fields are interactive controls that let users select options, toggle settings, or make choices. When these controls are built using ARIA roles instead of native HTML elements, the browser does not automatically derive a name from a <label> element or inner content the way it would for a native <input type="checkbox">. You must explicitly provide an accessible name so assistive technologies can announce the control’s purpose.
Without an accessible name, a screen reader might announce something like “checkbox, unchecked” with no indication of what the checkbox represents. This makes the interface unusable for people who are blind, deafblind, or who rely on voice control software. Users with mobility impairments who use speech recognition tools also depend on accessible names to target and activate controls by voice.
This rule applies to elements with the following ARIA roles:
-
checkbox -
menuitemcheckbox -
menuitemradio -
radio -
radiogroup -
switch
Related WCAG Success Criteria
This rule maps to WCAG 2.0, 2.1, and 2.2 Success Criterion 4.1.2: Name, Role, Value (Level A). This criterion requires that for all user interface components, the name and role can be programmatically determined. Toggle fields that lack an accessible name violate this requirement because assistive technologies cannot convey the control’s purpose to the user.
How to Fix It
You can provide an accessible name for ARIA toggle fields using any of these techniques:
- Inner text content — Place descriptive text inside the element. The browser uses this text as the accessible name.
-
aria-label— Add anaria-labelattribute with a descriptive string directly on the element. -
aria-labelledby— Reference theidof another element that contains the label text. Ensure the referenced element actually exists in the DOM. -
title— Use thetitleattribute as a last resort. While it does provide an accessible name, it is less discoverable for sighted users and not consistently exposed by all assistive technologies.
Important: If you use aria-labelledby, make sure the referenced id matches an element that exists and contains meaningful text. Pointing to a non-existent id results in no accessible name.
Examples
Incorrect: Toggle fields without accessible names
<!-- checkbox with a broken aria-labelledby reference -->
<div role="checkbox" aria-checked="false" aria-labelledby="nonexistent-id"></div>
<!-- menuitemcheckbox with no name -->
<ul role="menu">
<li role="menuitemcheckbox" aria-checked="true"></li>
</ul>
<!-- menuitemradio with no name -->
<ul role="menu">
<li role="menuitemradio" aria-checked="false"></li>
</ul>
<!-- radio with no name -->
<div role="radiogroup">
<div role="radio" aria-checked="false" tabindex="0"></div>
</div>
<!-- switch with no name and empty child spans -->
<div role="switch" aria-checked="true">
<span></span>
<span></span>
</div>
Each of these elements has no text content, no valid aria-label, no working aria-labelledby, and no title. A screen reader cannot announce what they represent.
Correct: Toggle fields with accessible names
<!-- checkbox: name from inner text content -->
<div role="checkbox" aria-checked="false" tabindex="0">
Subscribe to newsletter
</div>
<!-- menuitemcheckbox: name from aria-label -->
<ul role="menu">
<li role="menuitemcheckbox"
aria-checked="true"
aria-label="Word wrap">
</li>
</ul>
<!-- menuitemradio: name from aria-labelledby -->
<p id="font-label">Sans-serif</p>
<ul role="menu">
<li role="menuitemradio"
aria-checked="true"
aria-labelledby="font-label">
</li>
</ul>
<!-- radio: name from title -->
<div role="radiogroup" aria-label="Crust type">
<div role="radio"
aria-checked="false"
tabindex="0"
title="Regular Crust">
</div>
</div>
<!-- switch: name from aria-label -->
<div role="switch"
aria-checked="true"
aria-label="Dark mode"
tabindex="0">
<span>off</span>
<span>on</span>
</div>
Preferred: Use native HTML elements when possible
Native HTML elements come with built-in accessible name mechanisms and keyboard behavior. Whenever possible, prefer them over custom ARIA toggle fields:
<!-- Native checkbox with a label -->
<label>
<input type="checkbox"> Subscribe to newsletter
</label>
<!-- Native radio buttons with a fieldset -->
<fieldset>
<legend>Crust type</legend>
<label><input type="radio" name="crust" value="regular"> Regular Crust</label>
<label><input type="radio" name="crust" value="thin"> Thin Crust</label>
</fieldset>
Using native elements reduces the risk of accessibility issues and eliminates the need to manually manage roles, states, and keyboard interactions.
ARIA attributes communicate essential information about the state, properties, and roles of interface elements to assistive technologies like screen readers and braille displays. When these attributes contain invalid values, the communication breaks down entirely. A screen reader might ignore the attribute, misrepresent the element’s state, or behave unpredictably — any of which can make content unusable.
This issue has a critical impact on users who are blind, deafblind, or have mobility impairments who rely on assistive technology to navigate and interact with web content. For example, if a checkbox uses aria-checked="ture" instead of aria-checked="true", a screen reader cannot determine whether the checkbox is checked, leaving the user unable to understand the form’s current state.
This rule maps to WCAG 2.0, 2.1, and 2.2 Success Criterion 4.1.2: Name, Role, Value (Level A), which requires that for all user interface components, the name, role, and value can be programmatically determined and set by assistive technologies. Invalid ARIA values violate this criterion because the value cannot be meaningfully determined.
How to Fix It
For every aria- attribute in your markup, confirm that its value:
-
Is spelled correctly — a typo like
"flase"instead of"false"will cause a failure. - Is a permitted value for that specific attribute — each ARIA attribute accepts only certain value types.
- Makes sense in context — the value must be meaningful for the role and state of the element.
Understanding Value Types
Different ARIA attributes accept different types of values. Here are the most common:
-
true/false— Boolean values. Default is typically"false". Example:aria-hidden="true". -
tristate— Accepts"true","false", or"mixed". Example:aria-checked="mixed"for a partially selected checkbox. -
true/false/undefined— Liketrue/false, but"undefined"explicitly indicates the property is not relevant. -
token— One value from a limited set of allowed strings. Example:aria-sortaccepts"ascending","descending","none", or"other". -
token list— A space-separated list of one or more allowed tokens. Example:aria-relevant="additions text". -
ID reference— Theidof another element in the same document. Example:aria-labelledby="heading-1". -
ID reference list— A space-separated list of element IDs. Example:aria-describedby="desc1 desc2". -
integer— A whole number with no fractional part. Example:aria-level="2". -
number— Any real number. Example:aria-valuenow="3.5". -
string— An unconstrained text value. Example:aria-label="Close dialog".
For a complete reference of which values each attribute accepts, consult the WAI-ARIA 1.1 Supported States and Properties.
Watch Out for Common Pitfalls
-
Typos in boolean values —
"ture","flase","yes", and"no"are all invalid for attributes that expect"true"or"false". -
Using wrong tokens — Attributes like
aria-sort,aria-autocomplete, andaria-currentonly accept specific string values. -
Referencing non-existent IDs — If
aria-labelledbypoints to anidthat doesn’t exist in the document, the reference is invalid. -
Implicit defaults — Some roles change the default value of certain properties. For instance,
aria-expandedon acomboboxdefaults to"false"rather than"undefined". Be aware of role-specific defaults.
Examples
Incorrect: Misspelled Boolean Value
<div aria-hidden="flase">
This content should be visible to assistive technology.
</div>
The value "flase" is not a valid boolean. Assistive technologies may not be able to interpret the intended state.
Correct: Properly Spelled Boolean Value
<div aria-hidden="false">
This content is visible to assistive technology.
</div>
Incorrect: Invalid Token Value
<button aria-pressed="yes">
Bold
</button>
The aria-pressed attribute accepts "true", "false", or "mixed" — not "yes".
Correct: Valid Token Value
<button aria-pressed="true">
Bold
</button>
Incorrect: Invalid Tristate Value on a Checkbox
<div role="checkbox" aria-checked="partial" tabindex="0">
Select all items
</div>
The aria-checked attribute on a checkbox role only accepts "true", "false", or "mixed". The value "partial" is not recognized.
Correct: Valid Tristate Value on a Checkbox
<div role="checkbox" aria-checked="mixed" tabindex="0">
Select all items
</div>
Incorrect: Invalid Value for aria-sort
<th aria-sort="alphabetical">Name</th>
The aria-sort attribute only accepts "ascending", "descending", "none", or "other".
Correct: Valid Value for aria-sort
<th aria-sort="ascending">Name</th>
Incorrect: Non-Existent ID Reference
<input type="text" aria-labelledby="username-label">
<!-- No element with id="username-label" exists in the document -->
Correct: Valid ID Reference
<label id="username-label">Username</label>
<input type="text" aria-labelledby="username-label">
What This Rule Checks
The aria-valid-attr-value rule inspects every element that has one or more aria- attributes and verifies that each attribute’s value conforms to the allowed values defined in the WAI-ARIA specification. It checks for correct spelling, valid tokens, proper value types (boolean, integer, ID reference, etc.), and ensures that referenced IDs exist in the document.
When you add an ARIA attribute to an HTML element, the browser exposes that information through the accessibility tree so assistive technologies like screen readers can interpret it. If the attribute name is invalid — whether due to a typo like aria-hiden instead of aria-hidden, or a fabricated attribute like aria-visible that doesn’t exist in the spec — the browser won’t recognize it. The attribute is effectively dead code, and the accessibility enhancement you intended never reaches the user.
This is classified as a critical issue because the consequences can be severe. For example, if you misspell aria-required as aria-requried on a form field, screen reader users won’t be informed that the field is mandatory. If you misspell aria-expanded on a disclosure widget, blind and deafblind users won’t know whether a section is open or closed. Keyboard-only users who rely on screen readers are also affected when interactive states and properties fail to communicate correctly.
Related WCAG Success Criteria
This rule maps to WCAG Success Criterion 4.1.2: Name, Role, Value (Level A), which requires that for all user interface components, the name, role, and states/properties can be programmatically determined. Invalid ARIA attributes fail to communicate states and properties to assistive technologies, directly violating this criterion. This applies across WCAG 2.0, 2.1, and 2.2, as well as EN 301 549 (guideline 9.4.1.2).
How to Fix It
-
Audit your ARIA attributes. Review every attribute in your markup that starts with
aria-and confirm it matches a valid attribute name from the WAI-ARIA specification. -
Check for typos. Common mistakes include
aria-labelled-by(correct:aria-labelledby),aria-hiden(correct:aria-hidden), andaria-discribedby(correct:aria-describedby). -
Remove invented attributes. Attributes like
aria-visible,aria-tooltip, oraria-icondo not exist in the WAI-ARIA spec and will have no effect. -
Use tooling. IDE extensions, linters (like
eslint-plugin-jsx-a11y), and the axe DevTools browser extension can catch invalid ARIA attribute names during development.
Common Valid ARIA Attributes
Here are some frequently used ARIA attributes for reference:
-
Widget attributes:
aria-checked,aria-disabled,aria-expanded,aria-hidden,aria-label,aria-pressed,aria-readonly,aria-required,aria-selected,aria-valuenow -
Live region attributes:
aria-live,aria-atomic,aria-relevant,aria-busy -
Relationship attributes:
aria-labelledby,aria-describedby,aria-controls,aria-owns,aria-flowto -
Drag-and-drop attributes:
aria-dropeffect,aria-grabbed
Examples
Incorrect: Misspelled ARIA Attribute
<button aria-expandd="false">Show details</button>
The attribute aria-expandd is not a valid ARIA attribute. Screen readers will not announce the expanded/collapsed state of this button.
Incorrect: Non-Existent ARIA Attribute
<div aria-visible="true">Important announcement</div>
The attribute aria-visible does not exist in the WAI-ARIA specification. It will be completely ignored by assistive technologies.
Incorrect: Typo in a Relationship Attribute
<input type="text" aria-discribedby="help-text">
<p id="help-text">Enter your full name as it appears on your ID.</p>
The attribute aria-discribedby is a misspelling of aria-describedby. The input will not be associated with the help text for screen reader users.
Correct: Properly Spelled ARIA Attributes
<button aria-expanded="false">Show details</button>
<div aria-hidden="true">Decorative content</div>
<input type="text" aria-describedby="help-text">
<p id="help-text">Enter your full name as it appears on your ID.</p>
Each of these examples uses a valid, correctly spelled ARIA attribute that browsers and assistive technologies will recognize and process as intended.
When an <audio> element lacks a captions track, all of the information it conveys — dialogue, narration, sound effects, musical cues, and speaker identification — becomes completely inaccessible to users who are deaf or deafblind. This is considered a critical accessibility issue because it blocks entire groups of users from accessing content.
This rule relates to WCAG Success Criterion 1.2.1: Audio-only and Video-only (Prerecorded) (Level A), which requires that a text alternative be provided for prerecorded audio-only content. It also falls under Section 508 requirements and EN 301 549. Level A criteria represent the most fundamental accessibility requirements — failing to meet them means significant barriers exist for users with disabilities.
Captions vs. Subtitles
It’s important to understand that captions and subtitles are not the same thing:
-
Captions (
kind="captions") are designed for deaf and hard-of-hearing users. They include dialogue, speaker identification, sound effects (e.g., “[door slams]”), musical cues (e.g., “[soft piano music]”), and other meaningful audio information. -
Subtitles (
kind="subtitles") are language translations intended for hearing users who don’t understand the spoken language. They typically include only dialogue and narration.
Because of this distinction, you must use kind="captions", not kind="subtitles", to satisfy this rule.
How to Fix It
-
Create a captions file (typically in WebVTT
.vttformat) that includes all meaningful audio information: who is speaking, what they say, and relevant non-speech sounds. -
Add a
<track>element inside your<audio>element. -
Set the
kindattribute to"captions". -
Set the
srcattribute to the path of your captions file. -
Use the
srclangattribute to specify the language of the captions. -
Use the
labelattribute to give the track a human-readable name.
While only src is technically required on a <track> element, including kind, srclang, and label is strongly recommended for clarity and proper functionality.
Examples
Incorrect: <audio> with no captions track
<audio controls>
<source src="podcast.mp3" type="audio/mp3">
</audio>
This fails the rule because there is no <track> element providing captions.
Incorrect: <track> with wrong kind value
<audio controls>
<source src="podcast.mp3" type="audio/mp3">
<track src="subs_en.vtt" kind="subtitles" srclang="en" label="English">
</audio>
This fails because kind="subtitles" does not satisfy the captions requirement. Subtitles are not a substitute for captions.
Correct: <audio> with a captions track
<audio controls>
<source src="podcast.mp3" type="audio/mp3">
<track src="captions_en.vtt" kind="captions" srclang="en" label="English Captions">
</audio>
Correct: <audio> with multiple caption tracks for different languages
<audio controls>
<source src="interview.mp3" type="audio/mp3">
<track src="captions_en.vtt" kind="captions" srclang="en" label="English Captions">
<track src="captions_es.vtt" kind="captions" srclang="es" label="Subtítulos en español">
</audio>
Providing captions in multiple languages ensures broader accessibility and is especially helpful when your audience speaks different languages.
Example WebVTT captions file
A basic captions_en.vtt file might look like this:
WEBVTT
00:00:01.000 --> 00:00:04.000
[Upbeat intro music]
00:00:04.500 --> 00:00:07.000
Host: Welcome to the show, everyone.
00:00:07.500 --> 00:00:10.000
Guest: Thanks for having me!
00:00:10.500 --> 00:00:12.000
[Audience applause]
Notice how the captions include speaker identification (Host:, Guest:), non-speech sounds ([Upbeat intro music], [Audience applause]), and the full dialogue. This level of detail is what makes captions effective for deaf and deafblind users.
Why This Matters
The autocomplete attribute does more than enable browser autofill — it programmatically communicates the purpose of a form field to assistive technologies. This information is critical for several groups of users:
-
Screen reader users rely on the announced field purpose to understand what information is being requested. Without a valid
autocompletevalue, the screen reader may not convey this context clearly. - Users with cognitive disabilities benefit from browsers and assistive tools that can auto-populate fields or display familiar icons based on the field’s purpose, reducing the mental effort required to complete forms.
- Users with mobility impairments benefit from autofill functionality that minimizes the amount of manual input required.
- Users with low vision may use personalized stylesheets or browser extensions that adapt the presentation of form fields based on their declared purpose (e.g., showing a phone icon next to a telephone field).
This rule maps to WCAG 2.1 Success Criterion 1.3.5: Identify Input Purpose (Level AA), which requires that the purpose of input fields collecting user information can be programmatically determined. The autocomplete attribute is the standard mechanism for satisfying this requirement in HTML.
How the Rule Works
The axe rule autocomplete-valid checks that:
-
The
autocompleteattribute value is a valid token (or combination of tokens) as defined in the HTML specification for autofill. -
The value is appropriate for the type of form control it is applied to (e.g.,
emailis used on an email-type input, not on a checkbox). - The tokens are correctly ordered when multiple tokens are used (e.g., a section name followed by a hint token followed by the field name).
The rule flags fields where the autocomplete value is misspelled, uses a non-existent token, or is applied in an invalid way.
How to Fix It
- Identify all form fields that collect personal user information (name, email, address, phone number, etc.).
- Check if the data type matches one of the 53 input purposes defined in WCAG 2.1 Section 7.
-
Add the correct
autocompletevalue to each matching field. Make sure:- The value is spelled correctly.
- It is appropriate for the input type.
-
If using multiple tokens, they follow the correct order: optional section name (
section-*), optionalshippingorbilling, optionalhome,work,mobile,fax, orpager, and then the autofill field name.
-
Set
autocomplete="off"only when you have a legitimate reason to disable autofill — and note that this does not exempt you from the rule if the field still collects identifiable user data.
Common autocomplete Values
Here are some of the most frequently used values:
| Purpose |
autocomplete Value |
|---|---|
| Full name |
name |
| Given (first) name |
given-name |
| Family (last) name |
family-name |
| Email address |
email |
| Telephone number |
tel |
| Street address |
street-address |
| Postal code |
postal-code |
| Country |
country |
| Credit card number |
cc-number |
| Username |
username |
| New password |
new-password |
| Current password |
current-password |
Examples
Incorrect: Missing or Invalid autocomplete Values
<!-- Missing autocomplete attribute entirely -->
<label for="name">Full Name</label>
<input type="text" id="name" name="name">
<!-- Misspelled autocomplete value -->
<label for="email">Email</label>
<input type="email" id="email" name="email" autocomplete="emal">
<!-- Invalid autocomplete value -->
<label for="phone">Phone</label>
<input type="tel" id="phone" name="phone" autocomplete="phone-number">
In the examples above, the first field has no autocomplete attribute, the second has a typo (emal instead of email), and the third uses a non-standard value (phone-number instead of tel).
Correct: Valid autocomplete Values
<label for="name">Full Name</label>
<input type="text" id="name" name="name" autocomplete="name">
<label for="email">Email</label>
<input type="email" id="email" name="email" autocomplete="email">
<label for="phone">Phone</label>
<input type="tel" id="phone" name="phone" autocomplete="tel">
Correct: Using Multiple Tokens
When a form has separate shipping and billing sections, you can use additional tokens to distinguish them:
<fieldset>
<legend>Shipping Address</legend>
<label for="ship-street">Street Address</label>
<input type="text" id="ship-street" name="ship-street"
autocomplete="shipping street-address">
<label for="ship-zip">Postal Code</label>
<input type="text" id="ship-zip" name="ship-zip"
autocomplete="shipping postal-code">
</fieldset>
<fieldset>
<legend>Billing Address</legend>
<label for="bill-street">Street Address</label>
<input type="text" id="bill-street" name="bill-street"
autocomplete="billing street-address">
<label for="bill-zip">Postal Code</label>
<input type="text" id="bill-zip" name="bill-zip"
autocomplete="billing postal-code">
</fieldset>
Correct: Named Sections with section-*
You can use custom section names to group related fields when the same type of data appears multiple times:
<label for="home-tel">Home Phone</label>
<input type="tel" id="home-tel" name="home-tel"
autocomplete="section-home tel">
<label for="work-tel">Work Phone</label>
<input type="tel" id="work-tel" name="work-tel"
autocomplete="section-work tel">
By using valid, correctly applied autocomplete values, you ensure that assistive technologies can communicate the purpose of each field to users, browsers can offer reliable autofill, and your forms meet the requirements of WCAG 2.1 Success Criterion 1.3.5.
Some users need to adjust text spacing to make content readable. People with low vision may increase letter or word spacing to reduce visual crowding. People with cognitive disabilities, dyslexia, or attention deficit disorders often struggle to track lines of text that are tightly spaced — increasing line-height, letter-spacing, or word-spacing can make reading significantly easier.
When text-spacing properties are set inline with !important, they gain the highest specificity in the CSS cascade. This means user stylesheets, browser extensions, and assistive technology tools cannot override those values. The text becomes locked into a fixed spacing that may be difficult or impossible for some users to read.
This rule relates to WCAG 2.1 Success Criterion 1.4.12: Text Spacing (Level AA), which requires that no loss of content or functionality occurs when users adjust:
- Line height to at least 1.5 times the font size
- Spacing following paragraphs to at least 2 times the font size
- Letter spacing to at least 0.12 times the font size
- Word spacing to at least 0.16 times the font size
If inline !important declarations prevent these adjustments, the content fails this criterion.
How to Fix It
The fix is straightforward: do not use !important on inline style attributes for line-height, letter-spacing, or word-spacing. You have a few options:
-
Remove
!importantfrom the inline style declaration. Without!important, users can override the value with a custom stylesheet. - Move styles to an external or embedded stylesheet. This is generally the best approach because it separates content from presentation and gives users more control through the cascade.
-
If
!importantis truly necessary, apply it in a stylesheet rather than inline. Inline!importantstyles are virtually impossible for users to override, while stylesheet-level!importantcan still be overridden by user!importantrules.
Note that other inline style properties like font-size are not flagged by this rule — only the three text-spacing properties (line-height, letter-spacing, word-spacing) are checked.
Examples
Incorrect: Inline styles with !important
These examples fail because !important on inline text-spacing properties prevents user overrides.
<!-- line-height with !important — cannot be overridden -->
<p style="line-height: 1.5 !important;">
This text is locked to a specific line height.
</p>
<!-- letter-spacing with !important — cannot be overridden -->
<p style="letter-spacing: 2px !important;">
This text has fixed letter spacing.
</p>
<!-- word-spacing with !important — cannot be overridden -->
<p style="word-spacing: 4px !important;">
This text has fixed word spacing.
</p>
<!-- Mixed: word-spacing is fine, but letter-spacing has !important -->
<p style="word-spacing: 4px; letter-spacing: 2px !important; line-height: 1.8;">
Even one !important on a spacing property causes a failure.
</p>
Correct: Inline styles without !important
These examples pass because users can override the inline values with a custom stylesheet.
<!-- line-height without !important — overridable -->
<p style="line-height: 1.5;">
Users can adjust this line height with a custom stylesheet.
</p>
<!-- letter-spacing without !important — overridable -->
<p style="letter-spacing: 2px;">
Users can adjust this letter spacing.
</p>
<!-- word-spacing without !important — overridable -->
<p style="word-spacing: 4px;">
Users can adjust this word spacing.
</p>
<!-- Multiple spacing properties, all without !important -->
<p style="word-spacing: 4px; letter-spacing: 2px; line-height: 1.8;">
All three spacing properties can be overridden by the user.
</p>
<!-- font-size with !important is fine — not a text-spacing property -->
<p style="font-size: 200%;">
This does not trigger the rule.
</p>
Best practice: Use an external stylesheet instead
<!-- HTML -->
<p class="readable-text">
Styles are defined in the stylesheet, giving users full control.
</p>
/* CSS */
.readable-text {
line-height: 1.8;
letter-spacing: 0.05em;
word-spacing: 0.1em;
}
By keeping text-spacing styles in a stylesheet, you make it easy for users to apply their own overrides while maintaining your default design.
When a button lacks an accessible name, assistive technologies like screen readers can only announce it generically — for example, as “button” — with no indication of its purpose. This is a critical barrier for people who are blind or deafblind, as they rely entirely on programmatically determined names to understand and interact with interface controls. A sighted user might infer a button’s purpose from an icon or visual context, but without a text-based name, that information is completely lost to assistive technology users.
This rule maps to WCAG 2.0, 2.1, and 2.2 Success Criterion 4.1.2: Name, Role, Value (Level A), which requires that all user interface components have a name that can be programmatically determined. It is also covered by Section 508, EN 301 549 (9.4.1.2), and Trusted Tester guidelines, which require that the purpose of every link and button be determinable from its accessible name, description, or context.
How to fix it
Ensure every <button> element or element with role="button" has an accessible name through one of these methods:
- Visible text content inside the button element.
-
A non-empty
aria-labelattribute that describes the button’s purpose. -
An
aria-labelledbyattribute that references an element containing visible, non-empty text. -
A
titleattribute (use as a last resort, sincetitletooltips are inconsistently exposed across devices).
If a button is purely decorative and should be hidden from assistive technologies, you can assign role="presentation" or role="none" and remove it from the tab order with tabindex="-1". However, this is rare for interactive buttons.
Common mistakes to avoid
-
Leaving a
<button>element completely empty. -
Using only a
valueattribute on a<button>— unlike<input>elements, thevalueattribute on<button>does not provide an accessible name. -
Setting
aria-labelto an empty string (aria-label=""). -
Pointing
aria-labelledbyto an element that doesn’t exist or contains no text. - Using only an icon or image inside a button without providing alternative text.
Examples
Incorrect: empty button
<button id="search"></button>
A screen reader announces this as “button” with no indication of its purpose.
Incorrect: button with only a value attribute
<button id="submit" value="Submit"></button>
The value attribute does not set the accessible name for <button> elements.
Incorrect: empty aria-label
<button id="close" aria-label=""></button>
An empty aria-label results in no accessible name.
Incorrect: aria-labelledby pointing to a missing or empty element
<button id="save" aria-labelledby="save-label"></button>
<div id="save-label"></div>
The referenced element exists but contains no text, so the button has no accessible name.
Correct: button with visible text
<button>Submit order</button>
Correct: icon button with aria-label
<button aria-label="Close dialog">
<svg aria-hidden="true" focusable="false">
<use href="#icon-close"></use>
</svg>
</button>
The aria-label provides the accessible name, while aria-hidden="true" on the SVG prevents duplicate announcements.
Correct: button labeled by another element
<h2 id="section-title">Shopping cart</h2>
<button aria-labelledby="section-title">
<svg aria-hidden="true" focusable="false">
<use href="#icon-arrow"></use>
</svg>
</button>
The button’s accessible name is drawn from the referenced heading text.
Correct: button with aria-label and visible text
<button aria-label="Search products">Search</button>
When both aria-label and inner text are present, aria-label takes precedence as the accessible name. Use this when you need a more descriptive name than what the visible text alone conveys.
Correct: button with title (last resort)
<button title="Print this page">
<svg aria-hidden="true" focusable="false">
<use href="#icon-print"></use>
</svg>
</button>
The title attribute provides an accessible name, but visible text or aria-label are preferred because title tooltips may not be available to touch-screen or keyboard-only users.
Websites typically repeat navigation links, branding, and other interface elements across every page. While sighted mouse users can visually scan past these blocks and click wherever they want, keyboard-only users and screen reader users must navigate through every interactive element sequentially. Without a bypass mechanism, a keyboard user might need to press Tab dozens of times just to reach the primary content on each new page they visit. For users with severe motor impairments, this can take several minutes per page and cause fatigue or physical pain. Even users with less severe limitations will experience frustrating delays compared to mouse users, who can reach any link in a second or two.
Screen reader users also benefit significantly from bypass mechanisms. Landmarks like <main>, <nav>, and <header> allow screen readers to present a structural outline of the page, enabling users to jump directly to the section they need. Headings serve a similar purpose — screen reader users can navigate by heading level to quickly locate the main content area.
This rule maps to WCAG 2.4.1 Bypass Blocks (Level A), which requires that a mechanism is available to bypass blocks of content repeated on multiple pages. It is also required by Section 508 (specifically §1194.22(o)), the Trusted Tester guidelines, and EN 301 549. Because it is a Level A requirement, it represents the minimum baseline for accessibility compliance.
How the Rule Works
The axe bypass rule checks that a page includes at least one of the following:
-
A landmark region (such as
<main>,<nav>,<header>, or<footer>) -
A heading (an
<h1>through<h6>element) - An internal skip link (an anchor link that points to a location further down the page)
If none of these are present, the rule flags the page as a failure.
How to Fix It
The best approach is to use HTML5 landmark elements to structure your page. At a minimum, include a <main> element that wraps the primary content of the page. You should also use <header>, <nav>, and <footer> to identify other common sections. A page should have only one <main> landmark.
Additionally, consider adding a skip navigation link as the very first focusable element on the page. This provides an immediate shortcut for keyboard users who don’t use screen readers and may not be able to navigate by landmarks.
Prefer native HTML5 elements over their ARIA equivalents. For example, use <main> rather than <div role="main">. Native elements are better supported and require less code.
Examples
Incorrect: No Landmarks, Headings, or Skip Links
This page has no structural landmarks, no headings, and no skip link. Keyboard users must tab through every element to reach the content.
<div class="header">
<div class="logo">My Site</div>
<div class="nav">
<a href="/home">Home</a>
<a href="/about">About</a>
<a href="/contact">Contact</a>
</div>
</div>
<div class="content">
<p>This is the main content of the page.</p>
</div>
<div class="footer">
<p>Footer information</p>
</div>
Correct: Using HTML5 Landmark Elements
Replacing generic <div> wrappers with semantic HTML5 elements gives the page proper structure that assistive technologies can use for navigation.
<header>
<div class="logo">My Site</div>
<nav>
<a href="/home">Home</a>
<a href="/about">About</a>
<a href="/contact">Contact</a>
</nav>
</header>
<main>
<h1>Welcome</h1>
<p>This is the main content of the page.</p>
<section>
<h2>Latest News</h2>
<p>Section content here.</p>
</section>
</main>
<footer>
<p>Footer information</p>
</footer>
Correct: Adding a Skip Navigation Link
A skip link gives keyboard users an immediate way to bypass repeated content. It is typically visually hidden until it receives focus.
<body>
<a class="skip-link" href="#main-content">Skip to main content</a>
<header>
<nav>
<a href="/home">Home</a>
<a href="/about">About</a>
<a href="/contact">Contact</a>
</nav>
</header>
<main id="main-content">
<h1>Page Title</h1>
<p>This is the main content of the page.</p>
</main>
<footer>
<p>Footer information</p>
</footer>
</body>
.skip-link {
position: absolute;
left: -9999px;
top: auto;
width: 1px;
height: 1px;
overflow: hidden;
}
.skip-link:focus {
position: static;
width: auto;
height: auto;
overflow: visible;
}
When the skip link receives keyboard focus, it becomes visible, and pressing Enter moves focus directly to the <main> element. Combined with proper landmark elements, this gives all users fast, reliable access to the page’s primary content.
Screen readers announce definition lists in a specific way, conveying the relationship between terms (<dt>) and their descriptions (<dd>). When a <dl> element contains invalid direct children — such as <p>, <span>, or <li> elements — or when <dt> and <dd> elements appear in the wrong order, assistive technology cannot reliably parse the list. This primarily affects blind and deafblind users who depend on screen readers to understand content structure.
For example, a screen reader might announce a definition list by saying “definition list with 3 items,” then reading each term followed by its definition. If the markup is malformed, the screen reader may skip items, miscount them, or fail to associate terms with their definitions.
This rule maps to WCAG Success Criterion 1.3.1: Info and Relationships (Level A), which requires that information, structure, and relationships conveyed visually are also available programmatically. A properly structured <dl> ensures the semantic relationship between terms and definitions is preserved in the accessibility tree.
How to Fix It
Follow these rules when building definition lists:
-
Direct children of
<dl>must be limited to:<dt>,<dd>,<div>,<script>, or<template>elements. No other elements (like<p>,<span>,<li>, or plain text nodes) should appear as direct children. -
Ordering matters: One or more
<dt>elements must come before one or more<dd>elements. A<dd>should never precede a<dt>within a group. -
Using
<div>as a wrapper: You may wrap a<dt>/<dd>group in a<div>for styling purposes, but each<div>must contain a complete group (at least one<dt>followed by at least one<dd>). -
No stray content: Don’t place bare text or non-allowed elements directly inside the
<dl>.
Examples
Incorrect: Invalid direct child element
The <p> element is not a valid direct child of <dl>.
<dl>
<p>Beverage Types</p>
<dt>Coffee</dt>
<dd>A black hot drink made from roasted beans</dd>
</dl>
Incorrect: Wrong order of <dt> and <dd>
The <dd> element must follow the <dt>, not precede it.
<dl>
<dd>A black hot drink made from roasted beans</dd>
<dt>Coffee</dt>
</dl>
Incorrect: <dd> without a preceding <dt>
Every <dd> must be associated with at least one <dt>.
<dl>
<dd>An orphan definition with no term</dd>
</dl>
Correct: Basic definition list
<dl>
<dt>Coffee</dt>
<dd>A black hot drink made from roasted beans</dd>
<dt>Milk</dt>
<dd>A white cold drink</dd>
</dl>
Correct: Multiple definitions for a single term
<dl>
<dt>Coffee</dt>
<dd>A black hot drink made from roasted beans</dd>
<dd>A stimulating beverage containing caffeine</dd>
</dl>
Correct: Using <div> to wrap groups
Wrapping <dt>/<dd> groups in <div> elements is valid and useful for styling.
<dl>
<div>
<dt>Coffee</dt>
<dd>A black hot drink made from roasted beans</dd>
</div>
<div>
<dt>Milk</dt>
<dd>A white cold drink</dd>
</div>
</dl>
Correct: Multiple terms sharing one definition
<dl>
<dt>Latte</dt>
<dt>Café au lait</dt>
<dd>A coffee drink made with espresso and steamed milk</dd>
</dl>
Description lists follow a specific structural hierarchy in HTML. The <dl> element defines the list, and within it, <dt> elements represent terms while <dd> elements provide their corresponding descriptions. When <dt> or <dd> elements exist outside of a <dl>, the browser has no context to establish the relationship between terms and definitions. This makes the content semantically meaningless to assistive technologies.
Screen reader users are most affected by this issue. Screen readers announce description lists with specific cues — for example, telling users they’ve entered a list, how many items it contains, and the relationship between terms and descriptions. When <dt> and <dd> elements lack a <dl> parent, these announcements don’t occur, and users who are blind or deafblind lose important structural context. Keyboard-only users and users with mobility impairments who rely on assistive technologies are also affected, as their tools may not properly navigate orphaned list items.
This rule relates to WCAG 2.0, 2.1, and 2.2 Success Criterion 1.3.1: Info and Relationships (Level A), which requires that information, structure, and relationships conveyed through presentation can be programmatically determined. A description list’s structure conveys a meaningful relationship between terms and definitions, so the proper HTML hierarchy must be in place for that relationship to be communicated to all users.
How to fix it
-
Wrap orphaned
<dt>and<dd>elements inside a<dl>parent element. -
Ensure proper ordering —
<dt>elements should come before their associated<dd>elements. -
Only place
<dt>and<dd>elements (or<div>elements that group<dt>/<dd>pairs) as direct children of<dl>. -
Each
<dt>should have at least one corresponding<dd>, and vice versa, to form a complete term-description pair.
Examples
Incorrect: <dt> and <dd> without a <dl> parent
<dt>Coffee</dt>
<dd>A hot, caffeinated beverage</dd>
<dt>Milk</dt>
<dd>A cold, dairy-based drink</dd>
This is invalid because the <dt> and <dd> elements are not wrapped in a <dl>. Screen readers will not recognize these as a description list, and users will miss the term-definition relationships.
Correct: <dt> and <dd> wrapped in a <dl>
<dl>
<dt>Coffee</dt>
<dd>A hot, caffeinated beverage</dd>
<dt>Milk</dt>
<dd>A cold, dairy-based drink</dd>
</dl>
Correct: using <div> to group term-description pairs inside <dl>
HTML allows <div> elements as direct children of <dl> to group each <dt>/<dd> pair, which can be useful for styling:
<dl>
<div>
<dt>Coffee</dt>
<dd>A hot, caffeinated beverage</dd>
</div>
<div>
<dt>Milk</dt>
<dd>A cold, dairy-based drink</dd>
</div>
</dl>
Incorrect: <dd> nested inside an unrelated element
<div>
<dd>This description has no list context</dd>
</div>
A <dd> inside a <div> (or any non-<dl> parent) is invalid. Replace the <div> with a <dl> and add a corresponding <dt>:
<dl>
<dt>Term</dt>
<dd>This description now has proper list context</dd>
</dl>
The <title> element is the very first piece of information screen reader users hear when a page loads. It’s also what appears in browser tabs, bookmarks, and search engine results. When a page has no title — or has an empty or generic one like “Untitled” — screen reader users are forced to read through the page content to figure out its purpose. For users who navigate between multiple open tabs or use their browser history to find a previous page, missing or vague titles create serious barriers.
This rule relates to WCAG 2.4.2 Page Titled (Level A), which requires that web pages have titles describing their topic or purpose. Because this is a Level A criterion, it represents a minimum baseline for accessibility. The rule also aligns with Trusted Tester guideline 12.A and EN 301 549.
The users most affected by missing or poor page titles include:
- Screen reader users (blind and deafblind users), who rely on the title as the first orientation cue when a page loads
- Users with cognitive disabilities, who benefit from clear, descriptive titles to understand where they are
- Keyboard-only users and anyone navigating between multiple tabs, who use titles to distinguish pages
How to fix it
-
Add a
<title>element inside the<head>of every HTML document. -
Write meaningful text inside the
<title>— it must not be empty or contain only whitespace. - Make each title unique across your site so users can distinguish between pages.
- Put the most unique information first. If you include a site or brand name, place it at the end (e.g., “Contact Us – Acme Corp” rather than “Acme Corp – Contact Us”). This way, screen reader users hear the distinguishing content immediately instead of listening to the same brand name on every page.
-
Align the title with the page’s
<h1>heading. They don’t need to be identical, but they should be closely related since both describe the page’s purpose. - Avoid placeholder text like “Untitled,” “Page 1,” or “New Document.”
Beyond accessibility, descriptive titles improve SEO since search engines use them to filter, rank, and display results.
Examples
Incorrect: missing <title> element
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
</head>
<body>
<h1>Our Products</h1>
</body>
</html>
This page has no <title> element at all. Screen reader users will hear no identifying information when the page loads.
Incorrect: empty <title> element
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<h1>Our Products</h1>
</body>
</html>
A <title> element is present but contains no text, which is equivalent to having no title.
Incorrect: generic or placeholder title
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Untitled Document</title>
</head>
<body>
<h1>Our Products</h1>
</body>
</html>
While technically not empty, a placeholder title provides no useful information about the page’s content.
Correct: descriptive and unique title
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Our Products – Acme Corp</title>
</head>
<body>
<h1>Our Products</h1>
</body>
</html>
The title clearly describes the page content, places the unique information first, and includes the site name at the end for context. It also closely matches the <h1> heading on the page.
Ready to validate your sites?
Start your free trial today.