Tabs
Organize content into separate views where only one view is visible at a time. Aurora's Tabs integrates with the DS_URL_STATE adapter so the active tab is persisted in the URL by default.
html
<Tabs default-tab="overview">
<Tab name="overview" title="Overview">…</Tab>
<Tab name="metrics" title="Metrics">…</Tab>
<Tab name="history" title="History">…</Tab>
</Tabs>By default each Tab renders inside a styled card panel (white background, rounded corners, padding) that connects visually with the tab button. Use the headless prop on a Tab to disable this card chrome and take full control of the panel's appearance.
About the docs examples
Examples on this page use border to make the panel chrome visible against the white docs background. In an app with a tinted page background, the white panel reads on its own and the border isn't needed.
Two variants, two jobs
Picking the right variant matters more than the styling — it communicates hierarchy.
| Variant | Lives at | Mental model | Example |
|---|---|---|---|
primary | Page level | "Where am I globally?" | Energy / GHG / Water / Waste |
secondary | Inside a container (card, panel, modal) | "How do I want to view this?" | YoY / MoM / YTD · Chart / Table |
Primary tabs swap large portions of the page — feel like distinct states. Secondary tabs change how the same dataset is represented; the content stays the same, only the view changes.
Don't mix levels
Never stack two primary tab bars at the same level of a layout. If you need a sub-categorization, that's a secondary tab inside a panel — not another primary bar.
When to reach for tabs
- Switching between primary page sections that feel like distinct states (Energy / GHG / Water / Waste)
- Changing how a dataset is represented within a container (chart vs table, YoY vs MoM)
- Content fits neatly into 2–6 named categories with short labels
When not to use tabs
- More than ~6 categories — use a dropdown or side nav instead
- Navigating between major pages or routes — that's the top nav or sidebar's job, not tabs
- Triggering actions — use a button or button group
- Sorting or filtering data — use a dropdown or
SegmentedControl
Secondary variant
Sits inside a card, panel, or modal. Use to change the representation of a dataset — switching between chart and table view, time-window granularities, comparison modes.
html
<Tabs default-tab="overview" variant="secondary">
<Tab name="overview" title="Overview">…</Tab>
<Tab name="settings" title="Settings">…</Tab>
</Tabs>With leading icon
html
<Tab name="overview" title="Overview" leading-icon="home">…</Tab>
<Tab name="settings" title="Settings" leading-icon="settings">…</Tab>State indicators
Combine danger, warning, and missing flags to surface validation state on each tab.
html
<Tab name="ok" title="Complete">…</Tab>
<Tab name="warn" title="Has warnings" warning>…</Tab>
<Tab name="err" title="Has errors" danger>…</Tab>
<Tab name="missing" title="Missing data" missing>…</Tab>Disabled tab
html
<Tab name="locked" title="Locked" disabled>…</Tab>Tabs — Props
| Prop | Type | Default | Description |
|---|---|---|---|
defaultTab | string | — | name of the tab to open initially. |
variant | 'primary' | 'secondary' | 'primary' | Visual style. |
paramKey | string | 'tab' | URL query param the active tab is stored under. |
disableRouterUpdate | boolean | false | Don't write the active tab to the URL. |
border | boolean | false | Render a border around the active tab's panel. Useful when the page background doesn't already make a white panel visible. |
mobileTransparent | boolean | false | Use transparent background on small screens. |
Tab — Props
| Prop | Type | Default | Description |
|---|---|---|---|
name | string | required | Stable identifier matched against the URL param and defaultTab. |
title | string | required | Tab label text. |
leadingIcon | IconName | — | Icon shown before the title. |
leadingIconClass | string | — | Tailwind classes applied to the leading icon. |
trailingIcons | { icon: IconName; class?: string }[] | — | Icons shown after the title (e.g. count badges, status indicators). |
danger | boolean | false | Apply error-state styling to the tab. |
warning | boolean | false | Apply warning-state styling. |
missing | boolean | false | Apply missing-state styling. |
disabled | boolean | false | Disable the tab; cannot be selected. |
headless | boolean | false | Render the tab content without the default panel chrome. |
renderStrategy | 'lazy' | 'on-select' | 'pre-render' | 'lazy' | When the tab's content is mounted. |
Events
| Event | Description |
|---|---|
change | Emitted when the active tab changes. Receives (name: string). |
Adapter contract
Tabs reads and writes the active tab via DS_URL_STATE. Aurora's default URL-state adapter is a no-op, so out of the box the tab state lives in component state only. To enable URL persistence, provide a real adapter at the app root via provideUrlState(app).
Exposed methods
Tabs exposes a select(tabName) method via defineExpose — call tabs.value?.select('history') from a parent.
html
<Tabs ref="tabs" default-tab="overview">…</Tabs>