Example#
Pebblepath sells hand-thrown cups.
Usage#
Use tabs to split related content on one page into panels people read one at a time: a project's overview, its work and its numbers. Every panel should make sense on its own.
- The active tab is bolder and carries a 4 px ink rule; its width is reserved in advance, so nothing reflows when it changes.
- Activation. Arrow keys select tabs at once by default;
activation="manual"waits for Enter or Space, for panels that are heavy to render. - Overflow. A long list scrolls sideways with snap points, keeping the active tab in view. Prefer fewer tabs to scrolling ones.
- Content people compare belongs side by side, not in tabs. Steps in an order belong in a form or a list, not tabs.
Anatomy#
Pebblepath sells hand-thrown cups.
- ListThe tab row on a 2 px soft baseline.
.mk-tabs-list - Active tabWeight 700 and a 4 px ink rule.
.mk-tab[aria-selected="true"] - PanelFocusable when it holds nothing focusable.
.mk-tabs-panel
Volume#
Reading layer: identical at every volume.
Quiet
Pebblepath sells hand-thrown cups.
Studio
Pebblepath sells hand-thrown cups.
Press
Pebblepath sells hand-thrown cups.
Rave
Pebblepath sells hand-thrown cups.
Content#
- Tab labels are short nouns, one or two words, in sentence case: "Overview", "Work".
- Labels name what is in the panel, never what to do ("See work").
- If a tab would be empty, remove it rather than showing an empty panel.
Do and don't#
Do
Pebblepath sells hand-thrown cups.
Don't
- Step 1: your project
- Step 2: your budget
- Step 3: send
Accessibility#
- Arrows, Home and End move between tabs; activation is automatic unless
activation="manual". - A panel is a tab stop only when it holds nothing focusable.
| Keys | What happens |
|---|---|
| Tab | Moves to the active tab, then into its panel |
| LeftorRight | Move between tabs (and select them, unless activation is manual) |
| HomeorEnd | Jump to the first or the last tab |
| EnterorSpace | Select the focused tab (manual activation) |
The colour pairs it prints, with their contrast on both papers:
| Text | Surface | Role | Bone | Night |
|---|---|---|---|---|
--mk-ink | --mk-paper-hover | body-ui | 17.99:1 · Lc 103.4, passes | 16.94:1 · Lc 96.5, passes |
--mk-ink | --mk-paper-sunken-hover | body-ui | 16.63:1 · Lc 98.0, passes | 16.46:1 · Lc 96.3, passes |
--mk-ink | --mk-paper-plate-hover | body-ui | 16.90:1 · Lc 99.1, passes | 16.02:1 · Lc 96.0, passes |
Props#
| Prop | Type | Default | Description |
|---|---|---|---|
value | TabValue | none | |
defaultValue | TabValue | none | |
onValueChange | ((value: TabValue) => void) | none | |
activation | "automatic" | "manual" | none | `automatic` (default) selects on arrow keys; `manual` waits for Enter or Space. |
children required | ReactNode | none |
Tokens#
System tokens (16)
--mk-border--mk-border-heavy--mk-focus--mk-font-text--mk-radius-control--mk-rule-soft--mk-space-1--mk-space-4--mk-space-5--mk-text--mk-text-2--mk-text-disabled--mk-type-nav-leading--mk-type-nav-size--mk-type-nav-tracking--mk-type-nav-weight
Its own properties (1)
--mk-tabs-ring-room
Changelog#
Arrived in 0.1.0.
- The reading layer's controls, overlays, forms and visitor prefs (P2-T1 to P2-T5): every Button is the comic hit key, with IconButton, Link and Tooltip; Input, Textarea, Select, Checkbox and CheckboxGroup, Radio and RadioGroup, Switch, Slider with the ruler, RulerReadout and SegmentedControl; Dialog, Drawer, NavSheet, Tabs, Disclosure, Faq and faqJsonLd on Base UI 1.9 where the platform falls short; Field, Fieldset, Form with the site's inline validation, ErrorSummary, Callout, Honeypot, FormTimestamp and QuoteForm; PrefsScript under 1 KB, usePref and setPref with cross-tab sync, ThemeToggle and the visitor VolumeDial; VisuallyHidden.
- Tabs draw their 2 px baseline with plain fills (each tab under itself and the gap after it, and a filler to the list's end) instead of a background image on the list, so the list paints nothing behind its labels; it still sits at the tabs' foot and the focus ring still prints whole outside the tab. Read the whole entry
- SegmentedControl, Tabs and CodeBlock draw LC-05's ring outside the focused key (2 px at 2 px) instead of inset; RadioGroup and CheckboxGroup keys and cards, VolumeDial stops and link Cards mark the element that draws the ring (
data-mk-focus-ring); a focusable VisuallyHidden draws the ring. Read the whole entry