Library · Foundations

Tabs

A fully accessible tabs component following WAI-ARIA guidelines, with arrow-key navigation between tabs. Ships with four CSS skins — default (boxed), tabs-compact, tabs-underline, tabs-pill — applied via the class prop; skins live in primitives.css, not the vendored component.

Figma: Primitives / Tabs ↗
Default
---
import Tabs from "../components/primitives/tabs/Tabs.astro";
import TabsList from "../components/primitives/tabs/TabsList.astro";
import TabsTab from "../components/primitives/tabs/TabsTab.astro";
import TabsPanel from "../components/primitives/tabs/TabsPanel.astro";
---
<Tabs>
  <TabsList>
    <TabsTab id="tab-1" controls="panel-1" selected>Overview</TabsTab>
    <TabsTab id="tab-2" controls="panel-2">Details</TabsTab>
    <TabsTab id="tab-3" controls="panel-3">Support</TabsTab>
  </TabsList>
  <TabsPanel id="panel-1" labelledby="tab-1" selected>
    <p>A short overview of the product goes here.</p>
  </TabsPanel>
  <TabsPanel id="panel-2" labelledby="tab-2">
    <p>Detailed specifications and information live in this panel.</p>
  </TabsPanel>
  <TabsPanel id="panel-3" labelledby="tab-3">
    <p>Support resources and contact options appear here.</p>
  </TabsPanel>
</Tabs>
Compact
---
import Tabs from "../components/primitives/tabs/Tabs.astro";
import TabsList from "../components/primitives/tabs/TabsList.astro";
import TabsTab from "../components/primitives/tabs/TabsTab.astro";
import TabsPanel from "../components/primitives/tabs/TabsPanel.astro";
---
<Tabs class="tabs-compact">
  <TabsList>
    <TabsTab id="ctab-1" controls="cpanel-1" selected>Overview</TabsTab>
    <TabsTab id="ctab-2" controls="cpanel-2">Details</TabsTab>
    <TabsTab id="ctab-3" controls="cpanel-3">Support</TabsTab>
  </TabsList>
  <TabsPanel id="cpanel-1" labelledby="ctab-1" selected>
    <p>Same boxed style, compact density.</p>
  </TabsPanel>
  <TabsPanel id="cpanel-2" labelledby="ctab-2">
    <p>Detailed specifications and information live in this panel.</p>
  </TabsPanel>
  <TabsPanel id="cpanel-3" labelledby="ctab-3">
    <p>Support resources and contact options appear here.</p>
  </TabsPanel>
</Tabs>
Pill
---
import Tabs from "../components/primitives/tabs/Tabs.astro";
import TabsList from "../components/primitives/tabs/TabsList.astro";
import TabsTab from "../components/primitives/tabs/TabsTab.astro";
import TabsPanel from "../components/primitives/tabs/TabsPanel.astro";
---
<Tabs class="tabs-pill">
  <TabsList>
    <TabsTab id="ptab-1" controls="ppanel-1" selected>Overview</TabsTab>
    <TabsTab id="ptab-2" controls="ppanel-2">Details</TabsTab>
    <TabsTab id="ptab-3" controls="ppanel-3">Support</TabsTab>
  </TabsList>
  <TabsPanel id="ppanel-1" labelledby="ptab-1" selected>
    <p>Pill tabs work well for view switchers and filters.</p>
  </TabsPanel>
  <TabsPanel id="ppanel-2" labelledby="ptab-2">
    <p>Detailed specifications and information live in this panel.</p>
  </TabsPanel>
  <TabsPanel id="ppanel-3" labelledby="ptab-3">
    <p>Support resources and contact options appear here.</p>
  </TabsPanel>
</Tabs>
Underline
---
import Tabs from "../components/primitives/tabs/Tabs.astro";
import TabsList from "../components/primitives/tabs/TabsList.astro";
import TabsTab from "../components/primitives/tabs/TabsTab.astro";
import TabsPanel from "../components/primitives/tabs/TabsPanel.astro";
---
<Tabs class="tabs-underline">
  <TabsList>
    <TabsTab id="utab-1" controls="upanel-1" selected>Overview</TabsTab>
    <TabsTab id="utab-2" controls="upanel-2">Details</TabsTab>
    <TabsTab id="utab-3" controls="upanel-3">Support</TabsTab>
  </TabsList>
  <TabsPanel id="upanel-1" labelledby="utab-1" selected>
    <p>Underline tabs suit content-heavy pages and settings screens.</p>
  </TabsPanel>
  <TabsPanel id="upanel-2" labelledby="utab-2">
    <p>Detailed specifications and information live in this panel.</p>
  </TabsPanel>
  <TabsPanel id="upanel-3" labelledby="utab-3">
    <p>Support resources and contact options appear here.</p>
  </TabsPanel>
</Tabs>

Props

NameTypeRequiredDescription
class string Additional classes to apply to the tabs container
[key: string] unknown HTML attributes to spread on the tabs container
List: class string Additional classes to apply to the tabs list container
List: [key: string] unknown HTML attributes to spread on the tabs list
Tab: class string Additional classes to apply to the tab
Tab: id string Yes Unique identifier for the tab
Tab: controls string Yes ID of the panel this tab controls
Tab: selected boolean Whether this tab is currently selected (default: false)
Tab: [key: string] string | number | boolean | undefined HTML attributes to spread on the tab
Panel: class string Additional classes to apply to the panel
Panel: id string Yes Unique identifier for the panel
Panel: labelledby string Yes ID of the tab that labels this panel
Panel: selected boolean Whether this panel is currently selected (default: false)
Panel: [key: string] string | number | boolean | undefined HTML attributes to spread on the panel

Example with all props

<Tabs class="tabs-underline" data-section="docs">
  <TabsList class="product-tabs" aria-label="Product information">
    <TabsTab class="product-tab" id="tab-a" controls="panel-a" selected>Overview</TabsTab>
    <TabsTab id="tab-b" controls="panel-b">Details</TabsTab>
  </TabsList>
  <TabsPanel class="product-panel" id="panel-a" labelledby="tab-a" selected>
    <p>First panel content.</p>
  </TabsPanel>
  <TabsPanel id="panel-b" labelledby="tab-b">
    <p>Second panel content.</p>
  </TabsPanel>
</Tabs>