auditmysitev2.0.2

Tab list without an associated tab panel

aria/tabpanel-missing

WCAG success criterion
4.1.2 (level A)
Outcome class
Hint only. An automated check that by design reports review hints only: its findings are marked for manual review, never as confirmed violations.
Area
Accessibility, Technical Robustness
Default severity
medium
axe-core rule
aria-tablist-tabpanel

Why we flag this

Screen reader users cannot locate the content associated with a tab after activating it.

tablist without an accompanying tabpanel element.

What the rule checks

Scope. Tablists in the accessibility tree.

Expectation. Review per tablist when the document has no tabpanel at all: the tab list probably is navigation dressed up as tabs, or the panels lack their role. ARIA only describes the panel as usual, so never a violation. Any tabpanel in the document passes. Hidden subtrees are out of scope.

Source. WCAG 2.2 SC 1.3.1 and SC 4.1.2; WAI-ARIA 1.2 tabpanel ("typically" associated with a tab); APG Tabs pattern

Detection: shared; needs dom, ax_tree.

Failing example

The check flags this for review. Corpus case widget_patterns. The page may contain further findings for other rules.

widget_patterns.htmlHTML
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Widget pattern corpus case</title>
</head>
<body>
    <main>
        <h1>Accordion, tablist, and combobox patterns</h1>

        <!-- accordion-trigger-not-button: aria-expanded on a non-button element -->
        <div aria-expanded="false">Section 1 (div trigger)</div>

        <!-- accordion-no-controls: button trigger without aria-controls -->
        <button aria-expanded="false">Section 2</button>

        <!-- aria-tablist-tabpanel + aria-tab-selected-state: no tabpanel, no aria-selected -->
        <div role="tablist" aria-label="Sections">
            <div role="tab" id="tab1">Tab 1</div>
        </div>

        <!-- aria-combobox-options: listbox is a sibling, not a subtree descendant -->
        <div role="combobox" aria-expanded="true" aria-label="Fruit" tabindex="0"></div>
        <ul id="listbox1" role="listbox">
            <li role="option">Apple</li>
        </ul>
    </main>
</body>
</html>

Passing example

The check passes here and reports nothing. Corpus case aria_widgets_valid. The page may contain further findings for other rules.

aria_widgets_valid.htmlHTML
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Trail running shoe - Example shop</title>
</head>
<body>
    <header>
        <p>Example shop</p>
    </header>
    <main>
        <h1>Trail running shoe</h1>

        <!-- One tab selected, panel present -->
        <div id="product-tabs" role="tablist" aria-label="Product information">
            <button type="button" role="tab" id="tab-desc" aria-selected="true" aria-controls="panel-desc">Description</button>
            <button type="button" role="tab" id="tab-reviews" aria-selected="false" aria-controls="panel-desc" tabindex="-1">Reviews</button>
        </div>
        <div id="panel-desc" role="tabpanel" aria-labelledby="tab-desc">Lightweight shoe with a grippy sole.</div>

        <!-- Expanded combobox referencing its popup; a collapsed one needs no
             reference -->
        <label for="size">Size</label>
        <input id="size" type="text" role="combobox" aria-expanded="true" aria-autocomplete="list" aria-controls="size-options">
        <ul id="size-options" role="listbox" aria-label="Sizes">
            <li role="option" id="size-42" aria-selected="false">42</li>
            <li role="option" id="size-43" aria-selected="false">43</li>
        </ul>
        <label for="colour">Colour</label>
        <input id="colour" type="text" role="combobox" aria-expanded="false" aria-autocomplete="list">

        <!-- The native select has its popup built in -->
        <label for="qty">Quantity</label>
        <select id="qty"><option>1</option><option>2</option></select>

        <!-- A visible menu named by its heading -->
        <h2 id="sort-label">Sort reviews</h2>
        <div id="sort-menu" role="menu" aria-labelledby="sort-label">
            <div role="menuitem" id="sort-new" tabindex="0">Newest first</div>
            <div role="menuitem" id="sort-best" tabindex="-1">Best rated</div>
        </div>

        <!-- popovertarget points at a (closed, hence hidden) popover -->
        <button type="button" id="guide-btn" popovertarget="size-guide">Size guide</button>
        <div id="size-guide" popover>EU 42 equals UK 8.</div>

        <!-- Expanded button naming the region it controls -->
        <button type="button" id="care-btn" aria-expanded="true" aria-controls="care-text">Care instructions</button>
        <div id="care-text">Clean with a damp cloth.</div>

        <!-- Tooltips referenced as description and as name -->
        <button type="button" id="fav-btn" aria-describedby="fav-tip">Add to wish list</button>
        <div role="tooltip" id="fav-tip">Saved items stay for 30 days</div>
        <button type="button" id="share-btn" aria-labelledby="share-tip"><span aria-hidden="true">&#x2197;</span></button>
        <div role="tooltip" id="share-tip">Share</div>

        <!-- Open, operable popover -->
        <div id="promo" popover="manual" aria-label="Promotion">
            <p>10 % off your first order.</p>
            <button type="button" id="promo-close">Close</button>
        </div>
    </main>
    <footer>
        <p>Example shop</p>
    </footer>
    <script>
        document.getElementById('promo').showPopover();
    </script>
</body>
</html>

This page is generated from the rule catalogue and the rule contracts; see therule overview for how the outcome classes are derived.