Tabs
A row of tabs over their panels, showing one at a time when its module is loaded and all of them when it is not.
Example
View Code
<div class="tabs">
<div role="tablist" aria-label="Account">
<button type="button" role="tab" id="tab-profile" aria-controls="panel-profile">Profile</button>
<button type="button" role="tab" id="tab-billing" aria-controls="panel-billing">Billing</button>
</div>
<section role="tabpanel" id="panel-profile" aria-labelledby="tab-profile">
<p>Your name and how people reach you.</p>
</section>
<section role="tabpanel" id="panel-billing" aria-labelledby="tab-billing">
<p>Your plan and your invoices.</p>
</section>
</div>
When to use it
Alternative views of one thing: a profile and its billing, a chart and its table. Not for steps in a sequence, which want a form, and not for hiding content a reader needs to compare against something else.
How it works
A tab list of buttons over their panels. The CSS styles the list and marks the selected tab with the hue on its edge, and it never hides a panel. That is deliberate: a page that does not load tabs.js, or where the script fails, shows every panel under its own tab, so nothing a reader came for is locked away.
Load the module and it pairs every tab with the panel its aria-controls names, shows one, hides the rest, and takes over the keyboard: arrows move selection, Home and End jump to the ends, and only the selected tab is in the tab order, so Tab leaves the list rather than walking it.
<div class="tabs" data-orientation="vertical">
<div role="tablist" aria-label="Settings">
<button type="button" role="tab" id="t-general" aria-controls="p-general">General</button>
<button type="button" role="tab" id="t-keys" aria-controls="p-keys">API keys</button>
</div>
<section role="tabpanel" id="p-general" aria-labelledby="t-general"><p>General settings.</p></section>
<section role="tabpanel" id="p-keys" aria-labelledby="t-keys"><p>Your API keys.</p></section>
</div>
Accessibility
Name the tablist, since a page may have more than one. Each tab's aria-controls names its panel and each panel's aria-labelledby names its tab; the module reads that pairing rather than guessing from document order, so the markup stays the source of truth. The module also maintains aria-selected and the roving tabindex, which is what makes a tab list feel like one control rather than a row of buttons. Without the module the markup is still valid: the roles are right and every panel is readable.
Attributes
| Attribute | Type | Values | Default | Description |
|---|---|---|---|---|
data-orientation |
enum | horizontal, vertical |
horizontal |
Whether the tab list runs along the top or down the side. |
data-variant |
enum | primary, secondary, success, warning, alert, neutral |
primary |
The hue of the selected tab and its edge. |
data-gap |
enum | none, xs, sm, md, lg, xl, 2xl, 3xl, xs-sm, xs-md, xs-lg, xs-xl, xs-2xl, xs-3xl, sm-md, sm-lg, sm-xl, sm-2xl, sm-3xl, md-lg, md-xl, md-2xl, md-3xl, lg-xl, lg-2xl, lg-3xl, xl-2xl, xl-3xl, 2xl-3xl |
md |
Space between the list and the panels. |
Children
> [role="tablist"]: exactly 1. The tabs, in order, with a name of its own.[role="tab"]: at least 2. A button whose aria-controls names its panel.> [role="tabpanel"]: at least 2. A panel whose aria-labelledby names its tab.
Tokens
| Token | Description |
|---|---|
--yeti-tabs-border |
The line under or beside the list. |
--yeti-tabs-padding |
Padding of one tab. |
--yeti-border-width |
Width of that line; the selected mark is twice it. |
--yeti-space-md |
The default gap between the list and the panel. |
--yeti-color-primary |
The default variant's colour, when data-variant is absent. |
--yeti-color-primary-subtle |
The default variant's tint. |
--yeti-color-primary-soft |
The default variant's soft stop. |
--yeti-color-primary-strong |
The default variant's strong stop. |
--yeti-color-primary-text |
The default variant's text colour. |
--yeti-on-primary |
Text on the default variant's colour. |
--yeti-space-xs |
Gap between tabs. |
--yeti-weight-strong |
Weight of a tab's label. |
--yeti-duration-fast |
How long a tab takes to change colour. |
--yeti-ease |
The curve of that transition. |
Internal tokens (may change between minor versions)
- `--_yeti-variant` - `--_yeti-variant-subtle` - `--_yeti-variant-text` - `--_yeti-gap` - `--_yeti-variant-soft` - `--_yeti-variant-strong` - `--_yeti-on-variant`Accessibility
- Give the tablist a name with aria-label or aria-labelledby. Every tab is a button whose aria-controls names its panel, and every panel names its tab back with aria-labelledby; that pairing is what the module reads. With tabs.js loaded one tab is selected, the rest take tabindex="-1" for a roving focus, and the inactive panels are hidden. Without it nothing is hidden and every tab is focusable, which is plainer but never traps content.
| Key | Action |
|---|---|
Left / Right |
Moves selection along a horizontal list. |
Up / Down |
Moves selection along a vertical list. |
Home / End |
Selects the first or the last tab. |
Tab |
Leaves the list for the selected panel. |
Browser support
- Used without guards: logical properties
- Behind
@supports: nothing
JavaScript
Optional enhancement: components/tabs/tabs.js. The component works without it.
Available since 7.0.0.