Skip to content
Fleetline

Tabs

Usage

Use tabs to switch between related views of the same object without leaving the page: a van's overview, service history and documents. Don't use tabs for steps in a sequence (stepper) or to compare content side by side.

Anatomy

  1. Tab list — .tabs__list[role=tablist][aria-label]
  2. Tab — button.tabs__tab[role=tab] with aria-selected and aria-controls
  3. Count (optional) — .tabs__count
  4. Selected indicator — 2px bar + semibold + color
  5. Panel — .tabs__panel[role=tabpanel][aria-labelledby][tabindex=0]

Examples

Without JavaScript all panels are visible one after another; js/tabs.js hides the unselected ones. States marked hover, focus-visible and active are frozen with .is-hover, .is-focus-visible, .is-active. Those classes share their rule with the real pseudo-class, so what you see is exactly what users get. Never use them in product code.

Tabs

Van KX-219 · Ford Transit · 84,210 km · North Yard depot.

12 completed work orders since March 2024.

Next brake inspection due 14 November.

Registration, insurance and the last emissions test.

Automatic activation: arrow keys select as they move (panels are already loaded).

Overview for van KX-219.

Hover state.

Focus-visible state.

3 tasks: replace front pads, check rotors, road test.

Front brake pad set ×1, rotor ×2.

Available after the work order is closed.

Disabled tabs stay focusable so people find them; explain why near the tabs: "Invoice is available after closing."

Map of 42 vans in service.

List of 42 vans in service.

Today's jobs on a timeline.

Manual activation (Enter/Space) — the map is expensive to render.

North Yard depot: vans, mechanics and open work orders.

Harbor Road depot: vans, mechanics and open work orders.

Eastgate depot: vans, mechanics and open work orders.

Airport depot: vans, mechanics and open work orders.

Riverside depot: vans, mechanics and open work orders.

Old Town depot: vans, mechanics and open work orders.

Southport depot: vans, mechanics and open work orders.

Hill Street depot: vans, mechanics and open work orders.

Too many tabs for the width: the list scrolls with snap points. Arrow keys scroll the focused tab into view.

<div class="tabs tabs--underline">  <!-- add data-activation="manual" for expensive panels -->
  <div class="tabs__list" role="tablist" aria-label="Van KX-219">
    <button type="button" class="tabs__tab" role="tab" id="van-overview" aria-selected="true" aria-controls="van-overview-panel">Overview</button>
    <button type="button" class="tabs__tab" role="tab" id="van-history" aria-selected="false" aria-controls="van-history-panel">
      Service history <span class="tabs__count">12</span>
    </button>
    <button type="button" class="tabs__tab" role="tab" id="van-invoice" aria-selected="false" aria-controls="van-invoice-panel" aria-disabled="true">Invoice</button>
  </div>
  <div class="tabs__panel" role="tabpanel" id="van-overview-panel" aria-labelledby="van-overview" tabindex="0">…</div>
  <div class="tabs__panel" role="tabpanel" id="van-history-panel" aria-labelledby="van-history" tabindex="0">…</div>
  <div class="tabs__panel" role="tabpanel" id="van-invoice-panel" aria-labelledby="van-invoice" tabindex="0">…</div>
</div>
<script type="module">import { init } from "./js/tabs.js"; init();</script>

<!-- Tabs that change the URL are navigation: links + aria-current, no tab roles -->
<nav class="tabs tabs--underline" aria-label="Van KX-219 sections">
  <ul class="tabs__list">
    <li><a class="tabs__tab" href="/vehicles/KX-219" aria-current="page">Overview</a></li>
    <li><a class="tabs__tab" href="/vehicles/KX-219/history">Service history</a></li>
  </ul>
</nav>

API

HookValuesPurpose
.tabsblock classWrapper
.tabs--underline | --containedmodifierVisual variant
.tabs--overflowmodifierRoom for the scrollbar when tabs overflow
data-activation="manual"attributeSelect on Enter/Space instead of on focus
.tabs__list | __tab | __count | __icon | __panelpartsSee anatomy
aria-selected / aria-current="page"attributeSelected tab / current URL tab
aria-disabled="true"attributeUnavailable, focusable
tabs-changeeventFired on the tablist: detail { tab, panel }

Do and don't

Overview for van KX-219.

Service history for van KX-219.

Documents for van KX-219.

Do use short nouns for views of one object.

1. Check brakes for van KX-219.

2. Check tires for van KX-219.

3. Sign off for van KX-219.

Don't use tabs for ordered steps — use a stepper.

Accessibility

Keyboard interaction
KeyBehavior
TabMoves into the tab list (to the selected tab), then to the panel
← / →Previous / next tab, wrapping (mirrored in RTL); selects it with automatic activation
Home / EndFirst / last tab
Enter / SpaceSelects the focused tab (manual activation)

Tokens

Custom propertyPurpose
--color-text-mutedUnselected label
--color-selected-fg | -borderSelected label and bar
--color-action-ghost-bg-hoverHover
--color-border-defaultList baseline
--color-bg-subtle | -surface, --color-border-strongContained variant
--size-control-md | -smTab heights
--color-text-disabledDisabled tab