NavigationFlagship guide
Accessible Tabs
A set of layered sections of content, one visible at a time, selected via a tab list.
Last verified against WCAG 2.2 and WAI-ARIA APG 1.2 on 2026-07-02.
Implementation
Manage your name, photo, and public bio.
Change your password and manage two-factor authentication.
View invoices and update your payment method.
<div class="tabs">
<!-- The tablist. Each tab's aria-controls points at its panel; each
panel's aria-labelledby points back. Only the selected tab has
aria-selected="true" and tabindex="0" (roving tabindex). -->
<div role="tablist" aria-label="Account settings">
<button role="tab" id="tab-profile" aria-selected="true" aria-controls="panel-profile" tabindex="0">Profile</button>
<button role="tab" id="tab-billing" aria-selected="false" aria-controls="panel-billing" tabindex="-1">Billing</button>
<button role="tab" id="tab-security" aria-selected="false" aria-controls="panel-security" tabindex="-1">Security</button>
</div>
<div role="tabpanel" id="panel-profile" aria-labelledby="tab-profile" tabindex="0">…</div>
<div role="tabpanel" id="panel-billing" aria-labelledby="tab-billing" tabindex="0" hidden>…</div>
<div role="tabpanel" id="panel-security" aria-labelledby="tab-security" tabindex="0" hidden>…</div>
</div>Required roles, states & properties
| Element | Attribute | Why |
|---|---|---|
| Tab list wrapper | role="tablist" | Identifies the group of tab buttons as a tablist, so AT announces the total count and enables tab-specific navigation commands. |
| Each tab | role="tab" + aria-selected | Identifies each button as a tab and communicates which one is currently active, announced as "selected." |
| Each tab | aria-controls | Associates the tab with the panel id it reveals. |
| Each tab | tabIndex (roving) | Only the active/focused tab has tabIndex=0; the rest are -1, so Tab moves from the tablist straight to panel content instead of stopping on every tab. |
| Each panel | role="tabpanel" + aria-labelledby | Identifies the panel and labels it via the tab that reveals it, so its accessible name matches the tab label. |
Keyboard interaction model
| Key | Behavior |
|---|---|
| Tab | Moves focus from the page into the tablist (landing on the active tab), then out to the active panel's content. |
| Right / Left Arrow | Moves focus to the next / previous tab, wrapping at the ends. In automatic mode, also activates it. |
| Home / End | Moves focus to the first / last tab. |
| Enter / Space | In manual activation mode, activates the focused tab. Not needed in automatic mode. |
Focus management rules
- Tab into the widget lands on the currently active tab, never on an inactive one.
- Arrow keys move focus between tabs using a roving tabindex, never real DOM focus loss.
- Tab out of the tablist moves focus directly to the active panel's content, skipping inactive tabs entirely.
WCAG 2.2 success criteria mapping
| SC | Name | Level | Why it applies |
|---|---|---|---|
| 2.1.1 | Keyboard | A | All functionality is operable through a keyboard interface with no specific timing. |
| 2.4.3 | Focus Order | A | Focusable components receive focus in an order that preserves meaning and operability. |
| 3.2.1 | On Focus | A | Receiving focus does not trigger an unexpected change of context. |
| 4.1.2 | Name, Role, Value | A | For all UI components, name, role, and value are programmatically determinable; states and changes are announced. |