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.