tabs
A set of layered sections of content -- known as tab panels -- that are displayed one at a time.
Philosophy
Tabs organize content into parallel views — only one is visible at a time, but all are equally important. We keep the component controlled-optional (works with or without state management) because simple use cases shouldn't pay the complexity tax. The TabsList/TabsTrigger/TabsContent split keeps styling separate from behavior.
Installation
npx @gentleduck/cli add tabs
npx @gentleduck/cli add tabs
Usage
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'<Tabs
defaultValue="account"
className="w-[400px]"
>
<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><Tabs
defaultValue="account"
className="w-[400px]"
>
<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>Component Composition
API Reference
Tabs
| Prop | Type | Default | Description |
|---|---|---|---|
value | string | -- | Controlled active tab value. Must be used alongside onValueChange |
defaultValue | string | -- | Uncontrolled initial tab value |
onValueChange | (value: string) => void | -- | Callback fired when the active tab changes |
dir | 'ltr' | 'rtl' | -- | Text direction override. Resolved via useDirection (dir prop -> DirectionProvider -> 'ltr'). |
...props | Omit<React.HTMLProps<HTMLDivElement>, 'defaultValue'> | -- | Additional props to spread to the content div |
TabsList
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | -- | Additional CSS class names |
children | React.ReactNode | -- | TabsTrigger elements |
...props | React.HTMLProps<HTMLDivElement> | -- | Additional props to spread to the container div (renders with role="tablist") |
TabsTrigger
| Prop | Type | Default | Description |
|---|---|---|---|
value | string | (required) | A unique value that identifies this tab trigger |
defaultChecked | boolean | -- | If true, sets this tab as the default active tab on first render |
disabled | boolean | -- | Disables the tab trigger from user interaction |
className | string | -- | Additional CSS class names |
children | React.ReactNode | -- | Label or node to render inside the tab |
...props | React.HTMLProps<HTMLButtonElement> | -- | Additional props to spread to the button element |
TabsContent
| Prop | Type | Default | Description |
|---|---|---|---|
value | string | (required) | The associated value that matches a TabsTrigger |
forceMount | boolean | false | If true, the content stays mounted in the DOM even when hidden |
className | string | -- | Additional CSS class names |
children | React.ReactNode | -- | Tab panel content |
...props | React.HTMLProps<HTMLDivElement> | -- | Additional props to spread to the content div |
RTL Support
Direction is resolved through the shared primitives direction module. Use a local dir="rtl" override when the component exposes it, or set DirectionProvider at app/root level for global RTL/LTR behavior.