Skip to content

Tabs

Tabs switch between views of the same thing, in place, without leaving the page. Tabs sit in one box, and the open tab is filled with a 2px accent rule along its bottom.

CSS
css/components/tabs.css
JS
js/components/tabs.js

01 — Example

Tabs

Tabs sit side by side in one box. A count can sit beside a label, and a tab that isn't available yet can be disabled.

Taken on a Fujifilm X100V, 23mm, f/2.

02 — Behavior

Script

NameDetail
PairingTabs and panels pair up in order; the script wires the ids.
Keyboard← → move and select, Home and End jump, disabled tabs are skipped.
data-tabs-hashKeeps the open tab in the URL.
jewel:tabchangeFires on the .tabs when the tab changes.
el.jewelTabs.select(i)Opens a tab from a script.

03 — Usage

Use it for

  • Two to six views of the same thing: details, comments, a map.
  • Short labels, one or two words.

Avoid

  • Steps in a process. People expect to go back and forth freely.
  • Navigation between pages. Use links.
  • Content people need to compare side by side.

04 — Accessibility

Notes

  • Uses the ARIA tabs pattern: tablist, tab and tabpanel, with aria-selected.
  • Only the open tab is in the tab order; arrows move between tabs.

05 — Without Jewel’s JS

What the script does

The script selects a tab on a click or an arrow key, shows its panel and wires the ids. The CSS reads only the markup below, so a framework can set it itself and leave out tabs.js and data-component.

StateSet thisNotes
Selected tabaria-selected="true" and tabindex="0" on the tab; aria-selected="false" and tabindex="-1" on the restFilled, with the accent rule.
Panelshidden on every panel but the selected tab’sEach panel has role="tabpanel".
PairingAn id on each tab and panel; aria-controls on the tab, aria-labelledby on its panelTabs and panels pair up in order.
Panel focustabindex="0" on a panel with nothing focusable insideSo Tab moves into it.
Disableddisabled on the tabDimmed. Skip it with the arrow keys.

Events and keyboard

  • ← → move and select (↑ ↓ with aria-orientation="vertical" on the tablist), wrapping and skipping disabled tabs. Home and End jump to the ends. Focus follows the selection.
  • Scroll the selected tab into view when the row scrolls sideways.
  • Without the script, jewel:tabchange doesn’t fire and data-tabs-hash does nothing.