Standards · ARIA

Role Composite widget

tablist

Marks a container as the strip of tabs in a tabbed interface. Holds role="tab" children. Tabs and tabpanels are an ARIA-only pattern — there is no native HTML tablist.

When to use

Around the row (or column) of role="tab" elements in a tabbed interface. The tablist MUST have an accessible name via aria-label or aria-labelledby — without it, a screen-reader user hearing “tab list” cannot tell which tablist on the page it is.

Vertical tab strips need aria-orientation="vertical". The default is horizontal, so omit the attribute for horizontal tabs.

If your “tabs” are really navigation to other URLs, use <nav> with <a> links instead — the URL-changes-on-click pattern does not match tablist semantics.

Keyboard + focus contract

Per the APG tabs pattern:

  • Tab moves focus into the tablist and onto the selected tab; another Tab moves OUT (typically into the active tabpanel).
  • Left/Right arrows move focus between tabs (Up/Down for vertical tablists). Wraparound is optional but conventional.
  • Home / End jump to first / last tab.
  • Activation: in automatic mode, arrow keys both move focus AND select. In manual mode (recommended when activation is expensive), Space or Enter selects the focused tab.

The tablist itself does not handle focus — focus goes onto the tab, not the tablist container.

Common failures

  • Tablist with no accessible name. Multiple tablists on one page become indistinguishable.
  • All tabs have tabindex="0". The pattern is single-tab-stop; only the selected tab has tabindex="0".
  • Missing aria-orientation="vertical" on a vertical tablist — the screen reader instructs users to use Left/Right when the visual layout demands Up/Down.
  • role="tablist" wrapping links (<a href="#section">) instead of buttons. Anchor scroll-jumps the page and breaks the back button.
  • Tabpanel hidden via display: none AND hidden attribute when one is enough.

Example

<div role="tablist" aria-label="Project sections" aria-orientation="horizontal">
  <button role="tab" id="t-overview" aria-selected="true"  aria-controls="p-overview" tabindex="0">Overview</button>
  <button role="tab" id="t-files"    aria-selected="false" aria-controls="p-files"    tabindex="-1">Files</button>
  <button role="tab" id="t-team"     aria-selected="false" aria-controls="p-team"     tabindex="-1">Team</button>
</div>