Skip to content
Pandus

Accessible tabs (tablist)

Updated October 14, 2026 · 5 min read

Product pages often split description, specifications, delivery and reviews into tabs. Done right, tabs are quick to use with the keyboard. Done with div elements and click handlers, they hide most of the product information from keyboard and screen reader users. This page is part of the accessible UI patterns series.

When to use tabs

The APG defines tabs as "layered sections of content, known as tab panels, that display one panel of content at a time", where each panel has a tab that, when activated, displays it. Use tabs for a few related, parallel sections of similar weight that users switch between. Do not use them for:

  • Navigation between pages — those are links in a nav, even if styled as tabs; mark the current one with aria-current="page".
  • Long, sequential content or more than a handful of sections — use headings or an accordion.

Relevant WCAG criteria

Code example

<div class="tabs">
  <div 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-specs" aria-selected="false"
            aria-controls="panel-specs" tabindex="-1">Specifications</button>
    <button type="button" role="tab" id="tab-reviews" aria-selected="false"
            aria-controls="panel-reviews" tabindex="-1">Reviews (12)</button>
  </div>

  <div role="tabpanel" id="panel-desc" aria-labelledby="tab-desc" tabindex="0">…</div>
  <div role="tabpanel" id="panel-specs" aria-labelledby="tab-specs" tabindex="0" hidden>…</div>
  <div role="tabpanel" id="panel-reviews" aria-labelledby="tab-reviews" tabindex="0" hidden>…</div>
</div>

What the script must do:

  • Arrow keys move focus between tabs. This uses a roving tabindex: the active tab has tabindex="0", the others tabindex="-1", as described in the APG keyboard guide.
  • On activation: set aria-selected="true" on the new tab and false on all others, show its panel and hide the rest with hidden.
  • The tablist has aria-label, or aria-labelledby if there is a visible heading.
  • The APG says a panel "should set tabindex="0"" when it has no focusable content or its first content is not focusable, so Tab can reach it.
  • A vertical tab list gets aria-orientation="vertical" and uses Up and Down Arrow.

Keyboard interaction

From the APG tabs pattern (horizontal tab list):

Key Function
Tab Moves focus into the tab list onto the active tab; from the list, to the panel or the next element
Left Arrow Previous tab; from the first, wraps to the last. Optionally activates it
Right Arrow Next tab; from the last, wraps to the first. Optionally activates it
Space or Enter Activates the tab if it was not activated on focus
Home / End Optional: first or last tab
Delete Optional: closes a tab, if deletion is allowed

Automatic vs manual activation. The APG says "it is recommended that tabs activate automatically when they receive focus" if the panel is displayed without noticeable latency, which usually means its content is already loaded. If showing a panel needs a network request, automatic activation makes arrow navigation slow — then use manual activation with Space or Enter. The APG has examples of both.

Common mistakes on online shops

  • Tabs built as li or div elements with click handlers: no role, no keyboard, no selected state.
  • All tabs in the tab sequence and no arrow keys — or arrow keys, but role="tab" missing so screen readers do not announce "tab 2 of 3".
  • aria-selected stays true on the first tab after another one is chosen.
  • Panels hidden with opacity: 0 or moved off-screen but still readable and focusable.
  • Navigation styled as tabs with role="tab" while each "tab" loads a new page.
  • Reviews tab loaded by script and automatic activation that fires a request on every arrow key press.
  • The selected tab shown only by a slightly different colour.

What automated checks catch vs manual testing

Automated (axe-core rule) What it finds
aria-required-parent role="tab" that is not inside a tablist
aria-required-children role="tablist" without tab children
aria-valid-attr-value aria-controls/aria-labelledby pointing to missing IDs; invalid aria-selected
aria-allowed-attr Attributes that are not allowed on tab or tabpanel
button-name, aria-command-name Tabs without a name, for example icon-only tabs
duplicate-id-aria Duplicate IDs used by ARIA references
scrollable-region-focusable Scrollable panels that keyboard users cannot reach

All are cards in our rule library. Manual testing: Tab into the tab list, use the arrow keys, Home and End, check that only one tab is in the tab sequence, that the panel changes and that a screen reader announces the role, position and selected state. Check the visual indicator with the contrast checker.

Run the free one-page check on a product page. It is an automated check, not a full audit.

Frequently asked questions

Which ARIA roles do accessible tabs need?

A container with role="tablist" and a label, elements with role="tab" inside it, each with aria-selected and aria-controls, and panels with role="tabpanel" labelled by their tab.

How do keyboard users move between tabs?

Tab moves into the tab list onto the active tab; Left and Right Arrow move between tabs, wrapping at the ends; Home and End are optional; Tab again moves on to the panel. Only one tab is in the tab sequence.

Should a tab activate on focus or on Enter?

The APG recommends that tabs activate automatically when they receive focus, as long as the panel appears without noticeable delay. If the panel has to load first, use manual activation with Enter or Space.

Are tabs or an accordion better on a mobile product page?

Both can be accessible. Tabs need horizontal space and the full keyboard model; an accordion of disclosure buttons is simpler and works well on narrow screens. Many shops use tabs on desktop and an accordion on mobile.

Can an automated check test tabs?

It finds tab roles outside a tablist, tablists without tabs, aria-controls pointing to missing IDs and invalid aria-selected values. It cannot check arrow keys or whether aria-selected changes when another tab is chosen.

Sources

  • W3C WAI, APG Tabs pattern: https://www.w3.org/WAI/ARIA/apg/patterns/tabs/
  • W3C WAI, APG Developing a Keyboard Interface (roving tabindex): https://www.w3.org/WAI/ARIA/apg/practices/keyboard-interface/