auditmysitev2.0.2

Element outside its required parent context

aria/required-parent-missing

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
critical
axe-core rule
aria-required-parent

Why we flag this

Assistive technologies cannot convey the element's relationship to its group (e.g. a tab to its tab list).

Missing structural parent context for the ARIA role in use.

What the rule checks

Scope. Elements in the accessibility tree with an explicit role that has a required context role (tab, option, menuitem, row, cell, treeitem, ...), and <li> in a list re-roled to something else.

Expectation. Fails when the nearest ancestor with a role (generic and presentational ancestors are skipped, aria-owns counts as parent) is not one of the required context roles: a tab outside a tablist, a menuitem outside menu/menubar/group, a tab under a native <li> of a list re-roled as tablist. A tab inside its tablist, also through a generic wrapper or via aria-owns, passes. A listitem's context is lists/item-outside-list, not this id. Hidden subtrees are out of scope.

Source. WCAG 2.2 SC 1.3.1 and SC 4.1.2; WAI-ARIA 1.2 section 5.2.7 (Required Context Role); ACT ff89c9

Detection: shared; needs dom, ax_tree.

Failing example

The check reports a violation here. Corpus case aria_naming_roles, element div. The page may contain further findings for other rules.

aria_naming_roles.htmlHTML
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>ARIA role naming corpus case</title>
</head>
<body>
    <main>
        <h1>Widgets with role but no accessible name</h1>
        <div role="menuitem" tabindex="0"></div>
        <div role="slider" tabindex="0" aria-valuenow="5" aria-valuemin="0" aria-valuemax="10"></div>
        <div role="meter" aria-valuenow="5" aria-valuemin="0" aria-valuemax="10"></div>
        <div role="progressbar" aria-valuenow="50" aria-valuemin="0" aria-valuemax="100"></div>
        <div role="switch" tabindex="0" aria-checked="false"></div>
        <div role="tree" aria-label="Files"><div role="treeitem" tabindex="0"></div></div>
        <div role="dialog"></div>
    </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.