Accessibility Guides for blind
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.
The accesskey attribute provides a keyboard shortcut that lets users quickly activate or move focus to a specific element, typically by pressing the designated key in combination with a modifier key (such as Alt on Windows or Control + Option on macOS). When multiple elements share the same accesskey value, browsers handle the conflict inconsistently — some will focus the first matching element, others will cycle through matches, and some may ignore the duplicates entirely. This unpredictability undermines the purpose of access keys and creates a confusing experience.
This issue primarily affects users who rely on the keyboard to navigate, including people who are blind and use screen readers, users with low vision who cannot easily track a mouse pointer, and users with motor disabilities who depend on keyboards or keyboard-emulating input devices. For these users, a duplicated access key can mean they can never reach the intended element, or they reach the wrong one without realizing it.
This rule is classified as a Deque Best Practice. While it doesn’t map directly to a specific WCAG success criterion, it supports the broader principles behind WCAG 2.1.1 Keyboard (all functionality must be operable via keyboard) and WCAG 4.1.2 Name, Role, Value (user interface components must behave predictably). Duplicate access keys undermine keyboard operability by introducing unreliable shortcuts.
How to fix it
-
Find all elements on the page that use the
accesskeyattribute. -
Identify duplicates — any
accesskeyvalue that appears on more than one element. - Assign a unique value to each element so no two share the same key.
-
Avoid conflicts with default browser and screen reader shortcuts. For example, many browsers reserve
Alt + Dfor the address bar andAlt + Ffor the File menu.
A note of caution about accesskey
While fixing duplicates is important, be aware that the accesskey attribute has significant limitations in practice:
- Inconsistent browser support: Not all browsers implement access keys the same way, and modifier key combinations vary across operating systems.
- Conflict risk: Developer-defined access keys can override default browser or assistive technology shortcuts, potentially breaking expected functionality.
- Discoverability: Access keys are invisible to most users unless explicitly documented on the page.
-
Localization issues: A key that makes sense as a mnemonic in one language (e.g.,
sfor “Search”) may not work in another.
For these reasons, many accessibility experts recommend avoiding accesskey altogether and instead relying on well-structured headings, landmarks, and skip links for efficient keyboard navigation.
Examples
Incorrect: duplicate accesskey values
Both links use accesskey="g", so the browser cannot determine which element to activate.
<a href="https://google.com" accesskey="g">Link to Google</a>
<a href="https://github.com" accesskey="g">Link to GitHub</a>
Correct: unique accesskey values
Each link has a distinct accesskey value, so keyboard shortcuts work as expected.
<a href="https://google.com" accesskey="g">Link to Google</a>
<a href="https://github.com" accesskey="h">Link to GitHub</a>
Correct: removing accesskey in favor of better patterns
If access keys aren’t essential, consider removing them and providing clear navigation structure instead.
<nav aria-label="Main navigation">
<a href="https://google.com">Link to Google</a>
<a href="https://github.com">Link to GitHub</a>
</nav>
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 you assign a role like link, button, or menuitem to an element, you are telling the browser and assistive technologies that this element is an interactive command. Screen readers rely on the accessible name of these elements to communicate their purpose to the user. If no accessible name exists, a screen reader might announce something like “button” or “link” with no additional context — leaving the user with no way to understand what the control does.
This issue primarily affects users who are blind or have low vision and rely on screen readers, but it also impacts users with mobility impairments who may use voice control software to activate elements by name. If there is no name, voice control users cannot target the element with a spoken command.
Related WCAG Success Criteria
This rule maps to WCAG 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. It applies across WCAG 2.0, 2.1, and 2.2, and is also referenced in EN 301 549 (9.4.1.2), Trusted Tester guidelines, and RGAA.
The Trusted Tester guidelines further specify that the purpose of each link or button must be determinable from some combination of its text, accessible name, accessible description, or programmatically determined context.
How to Fix It
Ensure that every element with role="link", role="button", or role="menuitem" has an accessible name through one of these methods:
- Inner text content — Place readable text inside the element.
-
aria-labelattribute — Add a non-emptyaria-labelwith a descriptive name. -
aria-labelledbyattribute — Point to theidof another element that contains visible, non-empty text. -
titleattribute — Use atitleattribute as a fallback (thougharia-labelor visible text is preferred).
When possible, prefer using native HTML elements (<a>, <button>) over custom ARIA roles, as they come with built-in accessibility behaviors. If you must use ARIA roles, always make sure the accessible name is clear and describes the action or destination.
Examples
Incorrect: No accessible name
These elements will be flagged because screen readers cannot determine their purpose.
<!-- Empty element with no text or label -->
<div role="link"></div>
<!-- Empty aria-label provides no name -->
<div role="button" aria-label=""></div>
<!-- aria-labelledby points to a non-existent element -->
<div role="menuitem" aria-labelledby="nonexistent"></div>
<!-- aria-labelledby points to an empty element -->
<div role="link" aria-labelledby="empty-label"></div>
<div id="empty-label"></div>
Correct: Accessible name provided
Each of these elements has a discernible name that screen readers can announce.
<!-- Inner text content -->
<div role="link" tabindex="0">Visit our help center</div>
<!-- aria-label attribute -->
<div role="button" tabindex="0" aria-label="Close dialog"></div>
<!-- aria-labelledby pointing to visible text -->
<div role="menuitem" tabindex="0" aria-labelledby="menu-label">
<span id="menu-label">Save document</span>
</div>
<!-- Combination of aria-label and inner text -->
<div role="link" tabindex="0" aria-label="Learn more about pricing">
Learn more
</div>
<!-- title attribute as a fallback -->
<div role="button" tabindex="0" title="Submit form"></div>
Preferred: Use native HTML elements
Native elements handle naming and keyboard behavior automatically, reducing the chance of accessibility issues.
<a href="/help">Visit our help center</a>
<button type="button">Close dialog</button>
Note: When testing with RGAA, issues reported by this rule may need to be mapped to a different RGAA test, such as 6.2.1 for links.
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.
When a dialog appears on screen, assistive technologies announce it to the user along with its accessible name. This name gives essential context — it tells the user what the dialog is about, such as “Confirm deletion” or “Sign in to your account.” Without an accessible name, screen reader users hear that a dialog has opened but have no way to understand its purpose, which can be disorienting and make the interface difficult to use.
This issue primarily affects users who are blind or have low vision and rely on screen readers, as well as users with mobility impairments who navigate with assistive technology. It is flagged as a serious issue by the axe accessibility engine and aligns with Deque’s accessibility best practices.
How to Fix It
Ensure every element with role="dialog" or role="alertdialog" has an accessible name using one of these methods:
-
aria-label— Provide a concise, descriptive name directly on the dialog element. -
aria-labelledby— Reference theidof a visible element (typically a heading) inside the dialog that serves as its title. -
title— Use the HTMLtitleattribute as a fallback, thougharia-labeloraria-labelledbyare preferred.
Whichever method you choose, make sure the name clearly describes the dialog’s purpose. Avoid empty strings or references to elements that don’t exist or have no text content.
Examples
Incorrect: Dialog with No Accessible Name
The dialog has no aria-label, aria-labelledby, or title, so screen readers cannot announce its purpose.
<div role="dialog">
<h2>Unsaved Changes</h2>
<p>You have unsaved changes. Do you want to save before leaving?</p>
<button>Save</button>
<button>Discard</button>
</div>
Incorrect: Empty aria-label
An empty aria-label provides no useful information to assistive technologies.
<div role="alertdialog" aria-label="">
<p>An error occurred while saving your file.</p>
<button>OK</button>
</div>
Incorrect: aria-labelledby Pointing to a Nonexistent or Empty Element
If the referenced element doesn’t exist or contains no text, the dialog still has no accessible name.
<div role="dialog" aria-labelledby="dialog-title">
<p>Please confirm your selection.</p>
<button>Confirm</button>
</div>
<!-- No element with id="dialog-title" exists -->
<div role="dialog" aria-labelledby="dialog-title">
<span id="dialog-title"></span>
<p>Please confirm your selection.</p>
<button>Confirm</button>
</div>
Correct: Using aria-labelledby to Reference a Heading
The aria-labelledby attribute points to the dialog’s visible heading, giving it a clear accessible name.
<div role="dialog" aria-labelledby="dialog-title">
<h2 id="dialog-title">Unsaved Changes</h2>
<p>You have unsaved changes. Do you want to save before leaving?</p>
<button>Save</button>
<button>Discard</button>
</div>
Correct: Using aria-label
The aria-label attribute provides a concise name directly on the dialog.
<div role="alertdialog" aria-label="File save error">
<p>An error occurred while saving your file. Please try again.</p>
<button>Retry</button>
<button>Cancel</button>
</div>
Correct: Using the title Attribute
The title attribute works as a fallback naming mechanism, though aria-label or aria-labelledby are generally preferred because title has inconsistent support across assistive technologies.
<div role="dialog" title="Export Settings">
<p>Choose a format for your export.</p>
<select>
<option>PDF</option>
<option>CSV</option>
</select>
<button>Export</button>
<button>Cancel</button>
</div>
The aria-hidden attribute controls whether an element and its children are exposed to the accessibility tree — the data structure that assistive technologies use to interpret and present web content. When set to "true", the element and all of its descendants are hidden from screen readers and other assistive tools. Applying this attribute to the <body> element is catastrophic because the <body> contains all visible page content, meaning nothing on the page will be announced or navigable for assistive technology users.
This issue has a critical impact on users who are blind or have low vision and rely on screen readers. While sighted users can see and interact with the page normally, screen reader users experience a completely empty page. Keyboard users may still be able to tab to focusable elements like links and buttons, but the screen reader will remain silent — providing no context about what those elements are or what the page contains.
This rule relates to two WCAG 2.0/2.1/2.2 Level A success criteria:
- WCAG 1.3.1 (Info and Relationships): Content structure and relationships must be programmatically determinable. Hiding the entire body breaks this requirement because no structural information reaches assistive technologies.
-
WCAG 4.1.2 (Name, Role, Value): All user interface components must have accessible names and roles. When
aria-hidden="true"is on the<body>, no component can communicate its name, role, or value to assistive technologies.
How to Fix It
The fix is straightforward: remove the aria-hidden="true" attribute from the <body> element.
If aria-hidden="true" was added to the <body> intentionally — for example, as part of a modal dialog pattern — restructure your approach. Instead of hiding the entire body, hide only the background content behind the modal using aria-hidden="true" on sibling wrapper elements, or use the <dialog> element with the inert attribute on background content.
Here are some important things to keep in mind:
-
Never apply
aria-hidden="true"to the<body>element. There is no valid use case for this. -
Use
aria-hidden="true"sparingly and only on non-interactive, decorative, or redundant content that provides no value to screen reader users. -
Be cautious with
aria-hidden="false". It does not reliably re-expose content that is already hidden via CSS (display: none,visibility: hidden) or the HTMLhiddenattribute. Always test thoroughly if you rely on this approach.
Examples
Incorrect: aria-hidden="true" on the body
This makes the entire page inaccessible to assistive technologies:
<body aria-hidden="true">
<header>
<h1>Welcome to My Site</h1>
<nav>
<a href="/about">About</a>
<a href="/contact">Contact</a>
</nav>
</header>
<main>
<p>This content is invisible to screen readers.</p>
</main>
</body>
Correct: No aria-hidden on the body
Simply remove the attribute from the <body> element:
<body>
<header>
<h1>Welcome to My Site</h1>
<nav>
<a href="/about">About</a>
<a href="/contact">Contact</a>
</nav>
</header>
<main>
<p>This content is now accessible to everyone.</p>
</main>
</body>
Correct: Hiding background content behind a modal dialog
If your original intent was to hide background content while a modal is open, hide the background wrapper — not the <body>:
<body>
<div id="page-wrapper" aria-hidden="true">
<header>
<h1>Welcome to My Site</h1>
</header>
<main>
<p>Main page content hidden while modal is open.</p>
</main>
</div>
<div role="dialog" aria-modal="true" aria-labelledby="dialog-title">
<h2 id="dialog-title">Confirm Action</h2>
<p>Are you sure you want to proceed?</p>
<button>Yes</button>
<button>Cancel</button>
</div>
</body>
In this pattern, only the #page-wrapper is hidden from assistive technologies, while the dialog remains fully accessible. Remember to remove aria-hidden="true" from the wrapper when the dialog is closed.
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 meter role in ARIA represents a scalar measurement within a known range — think of a gauge showing a value like CPU temperature, password strength, or storage capacity. When a screen reader encounters an element with role="meter", it announces the element as a meter, but without an accessible name, it cannot convey what is being measured. The user hears something like “meter” with no context, which is effectively meaningless.
This issue primarily affects users who are blind or have low vision and rely on screen readers, as well as users with mobility impairments who may navigate via assistive technologies. It relates to WCAG 2.0/2.1/2.2 Success Criterion 1.1.1: Non-text Content (Level A), which requires that all non-text content has a text alternative that serves an equivalent purpose. A meter without a name fails to provide this text alternative.
How to Fix
Ensure every element with role="meter" has a clear, descriptive accessible name using one of these methods:
-
aria-label— Add descriptive text directly to the element. -
aria-labelledby— Reference another visible element that contains the label text. The referenced element must exist and contain non-empty text. -
title— Use thetitleattribute as a fallback naming method (thougharia-labeloraria-labelledbyare generally preferred).
The name should clearly describe what the meter is measuring so users understand its purpose in context.
Examples
Incorrect: Meter with no accessible name
The following meter has no name at all. A screen reader will announce it as a meter but cannot tell the user what it measures.
<div role="meter" aria-valuemin="0" aria-valuemax="100" aria-valuenow="75"></div>
Incorrect: Empty aria-label
An empty aria-label is equivalent to having no name.
<div role="meter" aria-label="" aria-valuemin="0" aria-valuemax="100" aria-valuenow="75"></div>
Incorrect: aria-labelledby referencing a nonexistent or empty element
If the referenced element doesn’t exist or has no text content, the meter still lacks an accessible name.
<div role="meter" aria-labelledby="nonexistent" aria-valuemin="0" aria-valuemax="100" aria-valuenow="75"></div>
<div role="meter" aria-labelledby="empty-label" aria-valuemin="0" aria-valuemax="100" aria-valuenow="75"></div>
<div id="empty-label"></div>
Correct: Using aria-label
<div role="meter" aria-label="Disk usage" aria-valuemin="0" aria-valuemax="100" aria-valuenow="75"></div>
Correct: Using aria-labelledby
<span id="meter-label">Battery level</span>
<div role="meter" aria-labelledby="meter-label" aria-valuemin="0" aria-valuemax="100" aria-valuenow="42"></div>
Correct: Using the title attribute
<div role="meter" title="Signal strength" aria-valuemin="0" aria-valuemax="5" aria-valuenow="3"></div>
Correct: Using the native <meter> element with a <label>
When possible, prefer the native HTML <meter> element, which has built-in semantics and can be associated with a <label>.
<label for="fuel">Fuel level</label>
<meter id="fuel" min="0" max="100" value="68">68%</meter>
When a progress bar lacks an accessible name, users who rely on assistive technologies have no way to distinguish it from other progress bars on the page or understand its purpose. Imagine a page with two progress bars—one for a file upload and one for a software installation. Without accessible names, a screen reader user would hear “progress bar” twice with no context for either. This issue primarily affects users who are blind or have low vision, as well as users with mobility impairments who may navigate using voice commands that reference element names.
This rule relates to WCAG Success Criterion 1.1.1: Non-text Content (Level A), which requires that all non-text content has a text alternative that serves the equivalent purpose. A progress bar is a non-text indicator of status, so it needs a text-based name to convey its meaning to assistive technology users. This criterion applies across WCAG 2.0, 2.1, and 2.2 at Level A, meaning it is a baseline requirement.
How to Fix
Ensure every element with role="progressbar" has a meaningful accessible name using one of these techniques:
-
aria-label— Provide a concise, descriptive label directly on the element. -
aria-labelledby— Reference theidof another element that contains visible label text. -
title— Use thetitleattribute as a fallback (thougharia-labeloraria-labelledbyare preferred).
The name should clearly describe what process or task the progress bar represents, such as “File upload progress” or “Installation progress.”
Examples
Failing: Progress bar with no accessible name
A progress bar with no labeling attributes is announced generically with no context.
<div role="progressbar" aria-valuenow="50" aria-valuemin="0" aria-valuemax="100">
</div>
Failing: Empty aria-label
An empty aria-label provides no name, so the progress bar remains unlabeled.
<div role="progressbar" aria-label="" aria-valuenow="25" aria-valuemin="0" aria-valuemax="100">
</div>
Failing: aria-labelledby pointing to a nonexistent or empty element
If the referenced element doesn’t exist or has no text content, the progress bar still has no accessible name.
<div role="progressbar" aria-labelledby="missing-id" aria-valuenow="75" aria-valuemin="0" aria-valuemax="100">
</div>
<!-- Or referencing an empty element -->
<div role="progressbar" aria-labelledby="empty-label" aria-valuenow="75" aria-valuemin="0" aria-valuemax="100">
</div>
<div id="empty-label"></div>
Passing: Using aria-label
<div role="progressbar" aria-label="File upload progress" aria-valuenow="50" aria-valuemin="0" aria-valuemax="100">
</div>
A screen reader will announce something like: “File upload progress, progress bar, 50%.”
Passing: Using aria-labelledby
<h3 id="upload-heading">Uploading resume.pdf</h3>
<div role="progressbar" aria-labelledby="upload-heading" aria-valuenow="70" aria-valuemin="0" aria-valuemax="100">
</div>
This approach is especially useful when a visible heading or label already describes the progress bar, keeping the visual and accessible names in sync.
Passing: Using title
<div role="progressbar" title="Installation progress" aria-valuenow="90" aria-valuemin="0" aria-valuemax="100">
</div>
The title attribute works as a naming mechanism, but note that it may also produce a tooltip on hover. Prefer aria-label or aria-labelledby when possible for a more consistent experience across assistive technologies.
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>
The role="text" attribute is a workaround for a specific screen reader behavior. When a text node is split by inline markup — for example, <h1>Good morning, <span>friend</span></h1> — VoiceOver on macOS and iOS may announce this as two separate phrases instead of reading it as one continuous string. Wrapping the content in an element with role="text" tells the screen reader to treat everything inside as a single text node, which produces a smoother reading experience.
However, role="text" comes with an important side effect: it overrides the semantic role of the container element and all of its descendants. Every child element is effectively treated as plain text. This means that if any descendant is focusable — such as an <a>, <button>, or <input> — the screen reader can no longer recognize it for what it is. The element remains in the tab order because the browser still considers it focusable, but VoiceOver will not announce its name, role, or value. The result is a “ghost” tab stop: the user presses Tab, focus moves to an element, but nothing is announced. This is a serious problem for blind users and keyboard-only users who rely on focus announcements to navigate and interact with a page.
Who is affected
-
Blind users using screen readers like VoiceOver cannot identify focusable elements trapped inside a
role="text"container. They encounter empty tab stops with no announcement. - Keyboard-only users experience confusing focus behavior — tabbing lands on elements that provide no information about what they are or what they do.
- Users with low vision who use screen readers in combination with magnification may also be impacted.
Related standards
This rule is classified as a Deque Best Practice. While it does not map directly to a specific WCAG success criterion, it relates closely to:
-
WCAG 4.1.2 (Name, Role, Value): All user interface components must have an accessible name and role that can be programmatically determined. A focusable element inside
role="text"loses its role and may lose its accessible name. - WCAG 2.4.7 (Focus Visible): Users must be able to understand where focus is. An empty tab stop with no screen reader announcement undermines this.
- WCAG 2.1.1 (Keyboard): All functionality must be operable through a keyboard. If a user cannot identify a focusable element, they effectively cannot use it.
How to fix it
-
Move focusable elements outside the
role="text"container so they retain their semantic roles and are properly announced. -
Only wrap non-interactive content with
role="text". Use it exclusively for its intended purpose: merging split text nodes into a single phrase for screen readers. -
Remove
role="text"entirely if the content includes interactive elements and you cannot restructure the markup. It is better to have VoiceOver announce text in separate phrases than to create inaccessible interactive elements.
Examples
Incorrect: focusable link inside role="text"
The link is inside the role="text" container, so VoiceOver treats it as plain text. The user can Tab to the link, but nothing is announced.
<p role="text">
For more details, visit
<a href="/about">our about page</a>.
</p>
Incorrect: focusable button inside role="text"
<div role="text">
Your session is about to expire.
<button>Extend session</button>
</div>
Correct: role="text" wraps only non-interactive content
The role="text" is applied to a <span> that contains no focusable elements, while the link sits outside it.
<p>
<span role="text">Good morning, <span>friend</span></span>.
Visit <a href="/dashboard">your dashboard</a> to get started.
</p>
Correct: role="text" on a heading with split text nodes
This is the primary use case for role="text" — ensuring VoiceOver reads a heading as a single phrase rather than separate fragments.
<h1>
<span role="text">Hello <br/>World</span>
</h1>
Correct: restructured to avoid the problem entirely
If you cannot separate interactive and non-interactive content, remove role="text" altogether.
<p>
For more details, visit
<a href="/about">our about page</a>.
</p>
The key principle is straightforward: role="text" is meant for presentation of static text only. Never place links, buttons, inputs, or any other focusable element inside it.
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.
Tooltips are supplementary text elements that appear when a user hovers over or focuses on a control. They typically provide descriptions, labels, or additional context. When an element has role="tooltip", assistive technologies recognize it as a tooltip and attempt to announce its name to the user.
If a tooltip lacks an accessible name, screen reader users hear something like “tooltip” with no accompanying description. This means they miss the very information the tooltip was designed to provide. Users affected include:
- Blind users who rely entirely on screen readers to access tooltip content.
- Low vision users who may use screen readers in combination with magnification and depend on announced text.
- Mobility-impaired users who navigate with keyboards or alternative input devices and rely on programmatic relationships to understand UI elements.
This rule relates to WCAG 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 applies across WCAG 2.0, 2.1, and 2.2, as well as EN 301 549 (guideline 9.4.1.2). Since this is a Level A requirement, it represents the minimum baseline for accessibility compliance.
How to Fix It
Ensure every element with role="tooltip" has a discernible accessible name through one of these methods:
- Inner text content — Place readable text directly inside the tooltip element.
-
aria-labelattribute — Set a non-emptyaria-labelwith a clear description. -
aria-labelledbyattribute — Reference another element’sidthat contains visible, non-empty text. -
titleattribute — Provide a non-emptytitleon the tooltip element (thougharia-labelor inner text are generally preferred).
The accessible name should be concise and clearly describe the information the tooltip is meant to communicate.
Examples
Incorrect: Empty Tooltip with No Accessible Name
The tooltip has no text content and no naming attribute, so screen readers cannot announce anything meaningful.
<button aria-describedby="tip1">Settings</button>
<div role="tooltip" id="tip1"></div>
Incorrect: Empty aria-label
An empty aria-label does not provide an accessible name.
<button aria-describedby="tip2">Save</button>
<div role="tooltip" id="tip2" aria-label=""></div>
Incorrect: aria-labelledby Pointing to a Non-Existent or Empty Element
If the referenced element doesn’t exist or has no text content, the tooltip has no accessible name.
<button aria-describedby="tip3">Delete</button>
<div role="tooltip" id="tip3" aria-labelledby="nonexistent"></div>
<button aria-describedby="tip4">Delete</button>
<div role="tooltip" id="tip4" aria-labelledby="empty-label"></div>
<div id="empty-label"></div>
Correct: Tooltip with Inner Text
The simplest approach — place descriptive text directly inside the tooltip element.
<button aria-describedby="tip5">Save</button>
<div role="tooltip" id="tip5">Save your current progress</div>
Correct: Tooltip with aria-label
Use aria-label when the tooltip’s visual content differs from what you want screen readers to announce, or when the tooltip is styled in a way that doesn’t use direct text content.
<button aria-describedby="tip6">Settings</button>
<div role="tooltip" id="tip6" aria-label="Open application settings"></div>
Correct: Tooltip with aria-labelledby
Reference another element that contains the descriptive text.
<button aria-describedby="tip7">Delete</button>
<div role="tooltip" id="tip7" aria-labelledby="tip7-label"></div>
<span id="tip7-label">Permanently delete this item</span>
Correct: Tooltip with title Attribute
The title attribute provides an accessible name as a fallback, though inner text or aria-label are generally more reliable across assistive technologies.
<button aria-describedby="tip8">Print</button>
<div role="tooltip" id="tip8" title="Print the current document"></div>
The treeitem role represents an item within a hierarchical tree widget, commonly used for file explorers, nested navigation menus, or collapsible category lists. When a treeitem lacks an accessible name, screen readers announce something like “tree item” with no further context, making it impossible for users who rely on assistive technology to distinguish one item from another or understand the tree’s structure.
This issue primarily affects screen reader users, but it can also impact users of voice control software who need to reference elements by name to interact with them.
This rule relates to WCAG 2.1 Success Criterion 4.1.2 (Name, Role, Value), which requires that all user interface components have a name that can be programmatically determined. It also supports Success Criterion 1.3.1 (Info and Relationships), ensuring that information conveyed through structure is available to all users.
How to Fix It
You can give a treeitem an accessible name in several ways:
- Inner text content — Place descriptive text directly inside the element.
-
aria-label— Add anaria-labelattribute with a descriptive string. -
aria-labelledby— Reference another element’sidthat contains the label text. -
titleattribute — Use thetitleattribute as a last resort (less reliable across assistive technologies).
The accessible name should be concise and clearly describe the item’s purpose or content.
Examples
Incorrect: treeitem with no accessible name
<ul role="tree">
<li role="treeitem"></li>
<li role="treeitem"></li>
</ul>
Screen readers announce these items as “tree item” with no distinguishing label.
Incorrect: treeitem with only a non-text child and no label
<ul role="tree">
<li role="treeitem">
<span class="icon-folder"></span>
</li>
</ul>
If the span renders only a CSS icon and contains no text, the treeitem still has no accessible name.
Correct: treeitem with visible text content
<ul role="tree">
<li role="treeitem">Documents</li>
<li role="treeitem">Photos</li>
<li role="treeitem">Music</li>
</ul>
Correct: treeitem with aria-label
<ul role="tree">
<li role="treeitem" aria-label="Documents">
<span class="icon-folder"></span>
</li>
<li role="treeitem" aria-label="Photos">
<span class="icon-folder"></span>
</li>
</ul>
Correct: treeitem with aria-labelledby
<ul role="tree">
<li role="treeitem" aria-labelledby="item1-label">
<span class="icon-folder"></span>
<span id="item1-label">Documents</span>
</li>
<li role="treeitem" aria-labelledby="item2-label">
<span class="icon-folder"></span>
<span id="item2-label">Photos</span>
</li>
</ul>
Correct: Nested treeitem elements with accessible names
<ul role="tree">
<li role="treeitem" aria-expanded="true">
Documents
<ul role="group">
<li role="treeitem">Resume.pdf</li>
<li role="treeitem">Cover Letter.docx</li>
</ul>
</li>
<li role="treeitem" aria-expanded="false">
Photos
</li>
</ul>
Every treeitem in the tree — including nested ones — must have an accessible name. When building tree widgets, also ensure proper keyboard interaction (arrow keys for navigation, Enter/Space for activation) and correct use of aria-expanded on parent items that contain child groups.
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.
Ready to validate your sites?
Start your free trial today.