auditmysitev2.0.2

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.

aria_attribute_validation.htmlHTML
<!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.

aria_roles_valid.htmlHTML
<!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.