tabpanel
Marks the content panel paired with a tab. Each tabpanel is labelled by its tab via aria-labelledby; the tab references the panel via aria-controls. Show one panel at a time; hide the others with the hidden attribute.
When to use
On the container that holds the content for a tab. Pair each tabpanel with its tab via aria-labelledby (pointing at the tab’s id). The tab in turn points at the panel with aria-controls. Hide inactive panels with the hidden attribute — not just display: none via CSS — so the accessibility tree mirrors the visual state.
If the panel contains interactive content (a form, a list of links), you may make the panel focusable with tabindex="0". That way, after activating a tab, the next Tab keystroke lands inside the panel.
If the panel contains a single focusable region — say one large heading followed by content — tabindex="0" on the panel is enough. If the panel is full of focusable controls, the user will Tab to them directly and the tabindex is optional.
Common failures
- Tabpanel hidden via CSS but not via the
hiddenattribute. Screen readers may still expose its content. - Tabpanel missing
aria-labelledby— announced as just “tab panel” with no name. - Tab points at a tabpanel id via
aria-controlsbut the panel does not point back viaaria-labelledby. The pairing must be reciprocal. - All tabpanels live in the DOM with
display: noneswitched dynamically, but nohiddenattribute. Auditors flag the inconsistency. - Putting
role="tabpanel"on a panel that is NOT paired with arole="tab"— orphan tabpanel.
Example
<div role="tablist" aria-label="Settings">
<button role="tab" id="t-account" aria-selected="true" aria-controls="p-account" tabindex="0">Account</button>
<button role="tab" id="t-billing" aria-selected="false" aria-controls="p-billing" tabindex="-1">Billing</button>
</div>
<section role="tabpanel" id="p-account" aria-labelledby="t-account" tabindex="0">
<h2>Account</h2>
<p>…</p>
</section>
<section role="tabpanel" id="p-billing" aria-labelledby="t-billing" tabindex="0" hidden>
<h2>Billing</h2>
<p>…</p>
</section>