Tabs
5 partsA set of layered sections of content — known as tab panels — where only one
panel is shown at a time, each surfaced by its own trigger. Use it to split
related content into switchable views without leaving the page: settings
panes, dashboards, or product detail sections.
The root owns the selected value (controlled via v-model or uncontrolled
via defaultValue), orientation, keyboard roving focus across triggers, and
provides context to every TabsList, TabsTrigger, and TabsContent.
Demo
Anatomy
Import the parts and compose them. Each part forwards attributes to its underlying element.
import {
TabsRoot,
TabsList,
TabsTrigger,
TabsContent,
TabsIndicator,
} from '@robonen/primitives/disclosure/tabs';
<TabsRoot>
<TabsList />
<TabsTrigger />
<TabsContent />
<TabsIndicator />
</TabsRoot>API Reference
TabsRoot
RootA set of layered sections of content — known as tab panels — where only one panel is shown at a time, each surfaced by its own trigger. Use it to split related content into switchable views without leaving the page: settings panes, dashboards, or product detail sections. The root owns the selected value (controlled via `v-model` or uncontrolled via `defaultValue`), orientation, keyboard roving focus across triggers, and provides context to every `TabsList`, `TabsTrigger`, and `TabsContent`.
| Prop | Type | Description |
|---|---|---|
modelValue? | Value | Controlled selected value. Bind with v-model. |
defaultValue? | Value | Uncontrolled initial value. |
orientation? | 'horizontal' | 'vertical' | Orientation of the tab list. |
dir? | RovingDirection | Writing direction. When omitted, inherits from a ConfigProvider,
falling back to 'ltr'. |
loop? | boolean | Wrap keyboard navigation. |
disabled? | boolean | Disable all tabs. |
activationMode? | 'automatic' | 'manual' | How tabs are activated. |
unmountOnHide? | boolean | Unmount inactive panels from the DOM instead of keeping them mounted but
hidden. When false, panels stay mounted (hidden) so their state/animation
survives switching. Individual panels can opt in via forceMount. |
TabsList
ListContainer that groups the tab triggers and exposes them as an ARIA `tablist`. Place one inside `TabsRoot`, wrapping the set of `TabsTrigger` elements.
No props or events — renders its element and forwards attributes.
TabsTrigger
TriggerThe clickable control that activates its associated `TabsContent` panel. Selecting it (by click or keyboard) sets the root value to its `value`. Render one per tab inside a `TabsList`.
| Prop | Type | Description |
|---|---|---|
value | TabsValue | Value that links this trigger to a content panel. |
disabled? | boolean | Disable this trigger. |
TabsContent
ContentThe panel shown when its matching `TabsTrigger` is active. Mounted via `Presence` so enter/leave transitions can run before it leaves the DOM; use `forceMount` to keep it mounted for custom animation, or rely on the root's `unmountOnHide` to keep inactive panels mounted-but-hidden. Pair one with each trigger via a shared `value`.
| Prop | Type | Description |
|---|---|---|
value | TabsValue | Value that links this panel to a trigger. |
forceMount? | boolean | Keep content mounted even when inactive. |
TabsIndicator
IndicatorAn optional visual cue (e.g. an underline or pill) that tracks the currently active trigger. Render it inside `TabsList`; it exposes the active tab's size and position as CSS variables (`--primitives-tabs-indicator-size` / `--primitives-tabs-indicator-position`) so consumers can animate a highlight purely from CSS.
No props or events — renders its element and forwards attributes.