Invalid ARIA role
aria/role-invalid
- WCAG success criterion
- 4.1.2 (level A)
- Outcome class
- Automatic. An automated check that can report a confirmed violation.
- Area
- Accessibility, Technical Robustness
- Default severity
- high
- axe-core rule
aria-roles
Why we flag this
Assistive technologies cannot determine the element's function.
Role value is not defined in the ARIA specification.
What the rule checks
Scope. Non-empty role attributes on elements in the accessibility tree.
Expectation. Fails when no token of the role attribute is a valid, non-abstract WAI-ARIA (or DPUB/ graphics module) role (role="tabel"): the element keeps its native or generic semantics. A fallback list whose unknown first token is followed by a valid one (role="upload button") passes, because user agents take the first valid token (ACT 674b10). Abstract roles are aria/role-abstract. Hidden subtrees are out of scope.
Source. WCAG 2.2 SC 4.1.2 Name, Role, Value; WAI-ARIA 1.2 section 5.4 (definition of roles) and 7.1 (role attribute, fallback tokens); ACT 674b10
Detection: shared; needs dom, ax_tree.
Failing example
The check reports a violation here. Corpus case aria_attribute_validation. The page may contain further findings for other rules.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>ARIA attribute validation corpus case</title>
</head>
<body>
<main>
<h1>Various ARIA attribute misuses</h1>
<!-- aria-attr-name-invalid: not a real ARIA attribute -->
<div aria-nonexistentattr="true">Unknown ARIA attribute</div>
<!-- aria-prohibited-attr: aria-label is prohibited on role="presentation" -->
<span role="presentation" aria-label="Redundant label">Decorative span</span>
<!-- aria-allowed-attr: aria-checked is not allowed on role="img" -->
<div role="img" aria-checked="true" aria-label="Icon">Icon</div>
<!-- aria-roles: not a real ARIA role -->
<div role="not-a-real-role">Invalid role value</div>
<!-- aria-valid-attr: aria-controls present but empty -->
<button aria-controls="" aria-label="Toggle">Toggle</button>
<!-- aria-valid-attr-value: aria-labelledby references a non-existent id -->
<p aria-labelledby="does-not-exist">Broken reference</p>
<!-- aria-required-parent: role="tab" outside a tablist -->
<div role="tab" tabindex="0">Orphan tab</div>
<!-- aria-hidden-focus: a focusable element inside aria-hidden -->
<div aria-hidden="true">
<button tabindex="0">Hidden but still focusable</button>
</div>
<!-- aria-invalid-without-describedby -->
<label for="email-field">Email</label>
<input id="email-field" type="email" aria-invalid="true">
</main>
</body>
</html>Passing example
The check passes here and reports nothing. Corpus case aria_roles_valid. The page may contain further findings for other rules.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Order overview - Example shop</title>
</head>
<body>
<header>
<p>Example shop</p>
</header>
<main>
<h1>Order overview</h1>
<!-- Valid concrete roles -->
<div id="orders" role="table" aria-label="Orders">
<div role="rowgroup">
<div role="row" id="order-head">
<span role="columnheader">Order</span>
<span role="columnheader">Status</span>
</div>
<div role="row" id="order-row">
<span role="cell">Order 1001</span>
<span role="cell">shipped</span>
</div>
</div>
</div>
<div id="filters" role="group" aria-label="Filter orders">
<button type="button" id="filter-open">Open orders</button>
</div>
<!-- A role that changes the element's semantics is not redundant -->
<a href="/orders/export" id="export" role="button">Export</a>
<!-- Tabs inside their tablist, through a generic wrapper; the tablist
owns a tab through aria-owns as well -->
<div id="views" role="tablist" aria-label="Views" aria-owns="view-map">
<div class="tab-wrap">
<div id="view-list" role="tab" tabindex="0" aria-selected="true" aria-controls="view-panel">List</div>
</div>
<div id="view-grid" role="tab" tabindex="-1" aria-selected="false" aria-controls="view-panel">Grid</div>
</div>
<div id="view-map" role="tab" tabindex="-1" aria-selected="false" aria-controls="view-panel">Map</div>
<div id="view-panel" role="tabpanel" aria-labelledby="view-list">Three orders.</div>
<!-- A busy feed may hold a placeholder instead of articles while loading -->
<div id="loading" role="feed" aria-busy="true" aria-label="Recent orders">
<p class="spinner">Loading</p>
</div>
<!-- Required states present; native controls carry them natively -->
<div id="gift" role="checkbox" tabindex="0" aria-checked="false">Gift wrap</div>
<div id="express" role="switch" tabindex="0" aria-checked="true">Express delivery</div>
<input type="checkbox" id="insure" role="switch">
<label for="insure">Insure parcel</label>
<div id="carrier" role="combobox" tabindex="0" aria-expanded="false" aria-controls="carriers" aria-label="Carrier">Standard</div>
<ul id="carriers" role="listbox" aria-label="Carriers" hidden>
<li role="option" id="carrier-std" aria-selected="true">Standard</li>
</ul>
<hr id="divider">
<div id="static-sep" role="separator"></div>
</main>
<footer>
<p>Example shop</p>
</footer>
</body>
</html>This page is generated from the rule catalogue and the rule contracts; see therule overview for how the outcome classes are derived.