Components
A set of layered sections of content — known as tab panels — that are displayed one at a time.
Playground
Make changes to your account here.
defaultValue and pair each TabsTrigger with the TabsContent that shares its value. Triggers live inside a single TabsList; only the active panel is rendered visible. Control the selection with value + onValueChange when the active tab must sync with URL or app state.Make changes to your account here.
import {
Tabs,
TabsContent,
TabsList,
TabsTrigger,
} from "@workspace/ui/components/tabs"
<Tabs defaultValue="account">
<TabsList>
<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>variant="line" on the TabsList drops the muted pill background and marks the active trigger with a 2px foreground underline instead — the classic browser-tabs look for page-level navigation sitting on the background.A summary of your workspace activity.
<Tabs defaultValue="overview">
<TabsList variant="line">
<TabsTrigger value="overview">Overview</TabsTrigger>
<TabsTrigger value="analytics">Analytics</TabsTrigger>
<TabsTrigger value="reports">Reports</TabsTrigger>
</TabsList>
<TabsContent value="overview">...</TabsContent>
</Tabs>orientation="vertical" on the root stacks the list beside the panel and switches arrow-key navigation to Up and Down. Triggers stretch to the list width and align their labels to the start; the line variant moves its indicator to the end edge.Make changes to your account here.
<Tabs defaultValue="account" orientation="vertical">
<TabsList variant="line">
<TabsTrigger value="account">Account</TabsTrigger>
<TabsTrigger value="password">Password</TabsTrigger>
<TabsTrigger value="settings">Settings</TabsTrigger>
</TabsList>
<TabsContent value="account">...</TabsContent>
</Tabs>Make changes to your account here.
<Tabs defaultValue="account">
<TabsList>
<TabsTrigger value="account">
<UserIcon />
Account
</TabsTrigger>
<TabsTrigger value="password">
<LockIcon />
Password
</TabsTrigger>
<TabsTrigger value="settings">
<GearSixIcon />
Settings
</TabsTrigger>
</TabsList>
<TabsContent value="account">...</TabsContent>
</Tabs>disabled to a TabsTrigger to block just that section — it dims to 50% opacity and is skipped by both pointer and keyboard navigation. Its panel stays unreachable until the trigger is enabled again.Make changes to your account here.
<Tabs defaultValue="account">
<TabsList>
<TabsTrigger value="account">Account</TabsTrigger>
<TabsTrigger value="password">Password</TabsTrigger>
<TabsTrigger value="billing" disabled>
Billing
</TabsTrigger>
</TabsList>
<TabsContent value="account">...</TabsContent>
</Tabs>dir prop (or the app-wide DirectionProvider), not from the surrounding markup — a dir="rtl" wrapper alone is not enough. With the prop set, arrow keys follow the reading direction and the vertical line indicator sticks to the logical end edge.قم بإجراء تغييرات على حسابك هنا.
<Tabs defaultValue="account" dir="rtl">
<TabsList>
<TabsTrigger value="account">الحساب</TabsTrigger>
<TabsTrigger value="password">كلمة المرور</TabsTrigger>
</TabsList>
<TabsContent value="account">قم بإجراء تغييرات على حسابك هنا.</TabsContent>
<TabsContent value="password">قم بتغيير كلمة المرور هنا.</TabsContent>
</Tabs>tablist, tab and tabpanel roles are wired up with aria-controls and aria-labelledby automatically. The list is a single Tab stop — arrow keys move between triggers (Home/End jump to the edges) and selection follows focus by default; set activationMode="manual" to require Enter or Space when switching panels is expensive.<Tabs defaultValue="account" activationMode="manual">
<TabsList>
<TabsTrigger value="account">Account</TabsTrigger>
<TabsTrigger value="password">Password</TabsTrigger>
</TabsList>
<TabsContent value="account">...</TabsContent>
<TabsContent value="password">...</TabsContent>
</Tabs>defaultValue or controlled via value + onValueChange. Orientation is set on the root and inherited by the list and triggers; the visual variant is set on the TabsList.| Component | Prop | Default |
|---|---|---|
| Tabs | defaultValue? / value?: string | — |
| Tabs | onValueChange?: (value: string) => void | — |
| Tabs | orientation?: "horizontal" | "vertical" | "horizontal" |
| Tabs | activationMode?: "automatic" | "manual" | "automatic" |
| Tabs | dir?: "ltr" | "rtl" | inherited |
| TabsList | variant?: "default" | "line" | "default" |
| TabsTrigger | value: string | required |
| TabsTrigger | disabled?: boolean | false |
| TabsContent | value: string | required |
| TabsContent | forceMount?: true | — |
<Tabs data-slot="tabs" data-orientation="horizontal|vertical" /> <TabsList data-slot="tabs-list" data-variant="default|line" /> <TabsTrigger data-slot="tabs-trigger" data-state="active|inactive" /> <TabsContent data-slot="tabs-content" data-state="active|inactive" />
Tokens used
10 design tokens consumed by the Tabs component.
--muted
Muted
--muted-foreground
Muted Foreground
--card
Card
--foreground
Foreground
--input
Input
--ring
Ring
--text-sm
Text Small (14px)
--radius-lg
Radius 1× (10px)
--radius-md
Radius 0.8× (8px)
--spacing
Spacing unit (4px)