Tabs

elements man ui/templates/tabs

Layered panels, one shown at a time, chosen from a list of tabs.

Example
import { Tabs, TabsList, TabsTrigger, TabsContent } from "@elements/ui/tabs"; <Tabs value="account"> <TabsList label="Settings"> <TabsTrigger value="account">Account</TabsTrigger> <TabsTrigger value="password">Password</TabsTrigger> </TabsList> <TabsContent value="account">Make changes to your account here.</TabsContent> <TabsContent value="password">Change your password here.</TabsContent> </Tabs>

Parts

Part What it is
Tabs The root. Owns value, the active tab.
TabsList The tablist: one tab stop, arrows between its triggers.
TabsTrigger A tab button. Activates the panel with the same value.
TabsContent A panel. Shown while its value is active, hidden otherwise.

Attributes

Tabs

Attribute Type Default Description
value string | null (two-way) "" The active tab. Empty selects the first enabled tab, already in the server HTML. null starts with no tab active and no panel.
orientation "horizontal" | "vertical" "horizontal" Lays the list out in a row or a column and picks the arrow keys.
activation "automatic" | "manual" "automatic" automatic activates a tab when it gets focus; manual waits for Enter or Space.
dir "" | "ltr" | "rtl" "" Reading direction. Empty inherits. Flips Left and Right.
loop boolean true Arrow keys wrap from the last tab to the first.
variant "line" | "segmented" "line" line underlines the active tab; segmented raises it on a muted track.
onValueChange (value: string, details: DisclosureDetails) => void () => {} Called when the user activates a tab, before the switch, with details second (reason, event, trigger, cancel(), isCanceled; reason none). details.cancel() keeps the current tab, for an unsaved-changes guard. Not called for changes the caller makes.
onTabDelete (value: string) => void undefined When set, Delete on a focused tab calls it so the caller can remove the tab; focus moves to the next tab.
class string "" Extra classes on the root.

TabsList

Attribute Type Default Description
label string "" aria-label for the tablist.
attrs Record<string, string | number | boolean | undefined> {} Other attributes for the tablist, such as aria-labelledby for a visible label. TabsContent takes attrs too.
class string "" Extra classes on the list.

TabsTrigger

Attribute Type Default Description
value string (required) Pairs the tab with its panel.
href string "" Renders the tab as a link (a[role=tab]): same tab stop and arrows; following it navigates.
disabled boolean false Cannot be activated; arrows skip it.
attrs Record<string, string | number | boolean | undefined> {} Other attributes for the button: id, title, data-*.
class string "" Extra classes on the tab.

TabsContent

Attribute Type Default Description
value string (required) Pairs the panel with its tab.
class string "" Extra classes on the panel.

Slots

Slot Part Content
default Tabs A TabsList and TabsContents.
default TabsList TabsTriggers.
default TabsTrigger The label: text, an <Icon>, or both.
default TabsContent The panel.

Keyboard

Keys Action
Tab Into the list, focuses the active tab; from a tab, moves to its panel.
ArrowRight / ArrowLeft Next or previous tab (horizontal, flipped right to left); activates it in automatic mode.
ArrowDown / ArrowUp Next or previous tab (vertical).
Home / End First or last tab.
Enter / Space Activates the focused tab (manual mode).
Delete Closes the focused tab when the root has onTabDelete.

Data attributes

Attribute Values On
data-orientation "horizontal" | "vertical" root, list, tab, panel
data-state "active" | "inactive" tab, panel
data-active present on the active tab tab
data-index the panel's position, from 0 panel
data-hidden present while the panel is inactive panel
data-disabled present when disabled tab

Accessibility

  • Follows the WAI-ARIA tabs pattern: role="tablist" with aria-orientation, role="tab" with aria-selected and aria-controls, role="tabpanel" with aria-labelledby.
  • Roving tabindex: the list is one tab stop, on the active tab. Panels are focusable so their text is reachable.
  • Inactive panels are hidden and stay mounted, so fields in other tabs keep their values.
  • The server renders the active tab and panel, so nothing moves when the page attaches.

See also