Tabs
Display one panel at a time, helping users switch between related views.
Overview
The Tabs component organises related content into separate panels. It is built on Base UI primitives and supports keyboard navigation, disabled tabs, animated indicators, optional separators, and URL-synced state.
Usage
import {
Tabs,
TabsContent,
TabsList,
TabsTrigger,
} from "@tilt-legal/cubitt-components/tabs";<Tabs defaultValue="account">
<TabsList>
<TabsTrigger value="account">Account</TabsTrigger>
<TabsTrigger value="settings">Settings</TabsTrigger>
<TabsTrigger value="billing">Billing</TabsTrigger>
</TabsList>
<TabsContent value="account">Account content</TabsContent>
<TabsContent value="settings">Settings content</TabsContent>
<TabsContent value="billing">Billing content</TabsContent>
</Tabs>Provide paramName to sync the active tab with the URL.
<Tabs defaultValue="account" paramName="tab">
<TabsList>
<TabsTrigger value="account">Account</TabsTrigger>
<TabsTrigger value="settings">Settings</TabsTrigger>
<TabsTrigger value="billing">Billing</TabsTrigger>
</TabsList>
<TabsContent value="account">Account content</TabsContent>
<TabsContent value="settings">Settings content</TabsContent>
<TabsContent value="billing">Billing content</TabsContent>
</Tabs>TabsTrigger forwards Base UI's polymorphic render support. When the trigger renders as something other than a native <button>, pass nativeButton={false}.
import { Link } from "@tanstack/react-router";
import {
Tabs,
TabsContent,
TabsList,
TabsTrigger,
} from "@tilt-legal/cubitt-components/tabs";
<Tabs defaultValue="overview">
<TabsList>
<TabsTrigger
nativeButton={false}
render={<Link href="/overview" />}
value="overview"
>
Overview
</TabsTrigger>
<TabsTrigger value="usage">Usage</TabsTrigger>
</TabsList>
<TabsContent value="overview">Overview content</TabsContent>
<TabsContent value="usage">Usage content</TabsContent>
</Tabs>Examples
Default
import { Card, CardContent } from "@tilt-legal/cubitt-components/card";
import {
Tabs,
TabsContent,
TabsList,
TabsTrigger,
} from "@tilt-legal/cubitt-components/tabs";
export default function Component() {
return (
<Tabs className="w-full max-w-md" defaultValue="account">
<TabsList className="mb-4">
<TabsTrigger value="account">Account</TabsTrigger>
<TabsTrigger value="settings">Settings</TabsTrigger>
<TabsTrigger value="billing">Billing</TabsTrigger>
</TabsList>
<Card>
<CardContent>
<TabsContent value="account">Account content</TabsContent>
<TabsContent value="settings">Settings content</TabsContent>
<TabsContent value="billing">Billing content</TabsContent>
</CardContent>
</Card>
</Tabs>
);
}Line
import {
Tabs,
TabsContent,
TabsList,
TabsTrigger,
} from "@tilt-legal/cubitt-components/tabs";
export default function Component() {
return (
<Tabs className="w-full max-w-md" defaultValue="account">
<TabsList className="mb-4" variant="line">
<TabsTrigger value="account">Account</TabsTrigger>
<TabsTrigger value="settings">Settings</TabsTrigger>
<TabsTrigger value="billing">Billing</TabsTrigger>
</TabsList>
<TabsContent value="account">Account content</TabsContent>
<TabsContent value="settings">Settings content</TabsContent>
<TabsContent value="billing">Billing content</TabsContent>
</Tabs>
);
}Separator
Use TabsSeparator inside the default track to separate groups of tabs. The separator fades while the selected pill touches either side of it.
import {
Tabs,
TabsContent,
TabsList,
TabsSeparator,
TabsTrigger,
} from "@tilt-legal/cubitt-components/tabs";
export default function Component() {
return (
<Tabs className="w-full max-w-md" defaultValue="account">
<TabsList className="mb-4">
<TabsTrigger value="account">Account</TabsTrigger>
<TabsTrigger value="settings">Settings</TabsTrigger>
<TabsSeparator />
<TabsTrigger value="billing">Billing</TabsTrigger>
</TabsList>
<TabsContent value="account">Account content</TabsContent>
<TabsContent value="settings">Settings content</TabsContent>
<TabsContent value="billing">Billing content</TabsContent>
</Tabs>
);
}Sizes
import {
Tabs,
TabsList,
TabsTrigger,
} from "@tilt-legal/cubitt-components/tabs";
export default function Component() {
return (
<div className="flex w-full flex-col items-center gap-12 py-6">
<Tabs defaultValue="account">
<TabsList size="sm">
<TabsTrigger value="account">Account</TabsTrigger>
<TabsTrigger value="settings">Settings</TabsTrigger>
<TabsTrigger value="billing">Billing</TabsTrigger>
</TabsList>
</Tabs>
<Tabs defaultValue="account">
<TabsList size="md">
<TabsTrigger value="account">Account</TabsTrigger>
<TabsTrigger value="settings">Settings</TabsTrigger>
<TabsTrigger value="billing">Billing</TabsTrigger>
</TabsList>
</Tabs>
<Tabs defaultValue="account">
<TabsList size="lg">
<TabsTrigger value="account">Account</TabsTrigger>
<TabsTrigger value="settings">Settings</TabsTrigger>
<TabsTrigger value="billing">Billing</TabsTrigger>
</TabsList>
</Tabs>
</div>
);
}Disabled
import {
Tabs,
TabsContent,
TabsList,
TabsTrigger,
} from "@tilt-legal/cubitt-components/tabs";
export default function Component() {
return (
<Tabs className="w-full max-w-md" defaultValue="account">
<TabsList className="mb-4">
<TabsTrigger value="account">Account</TabsTrigger>
<TabsTrigger disabled value="settings">
Settings
</TabsTrigger>
<TabsTrigger value="billing">Billing</TabsTrigger>
</TabsList>
<TabsContent value="account">Account content</TabsContent>
<TabsContent value="billing">Billing content</TabsContent>
</Tabs>
);
}Animated Height
Combine tabs with AutoResize for smooth height transitions between tab panels.
import { AutoResize } from "@tilt-legal/cubitt-components/auto-resize";
import {
Tabs,
TabsContent,
TabsList,
TabsTrigger,
} from "@tilt-legal/cubitt-components/tabs";
export default function Component() {
return (
<Tabs className="w-full max-w-md" defaultValue="account">
<TabsList className="mb-4">
<TabsTrigger value="account">Account</TabsTrigger>
<TabsTrigger value="settings">Settings</TabsTrigger>
<TabsTrigger value="billing">Billing</TabsTrigger>
</TabsList>
<AutoResize>
<TabsContent value="account">Short panel</TabsContent>
<TabsContent value="settings">A taller settings panel</TabsContent>
<TabsContent value="billing">Billing panel</TabsContent>
</AutoResize>
</Tabs>
);
}URL State
This example syncs with the demo-tab URL parameter.
import {
Tabs,
TabsContent,
TabsList,
TabsTrigger,
} from "@tilt-legal/cubitt-components/tabs";
export default function Component() {
return (
<Tabs
className="w-full max-w-md"
defaultValue="account"
paramName="demo-tab"
>
<TabsList className="mb-4">
<TabsTrigger value="account">Account</TabsTrigger>
<TabsTrigger value="settings">Settings</TabsTrigger>
<TabsTrigger value="billing">Billing</TabsTrigger>
</TabsList>
<TabsContent value="account">Account content</TabsContent>
<TabsContent value="settings">Settings content</TabsContent>
<TabsContent value="billing">Billing content</TabsContent>
</Tabs>
);
}API Reference
Tabs
The root component for a tabbed interface.
| Prop | Type | Default | Description |
|---|---|---|---|
defaultValue | string | — | The default active tab when uncontrolled. |
value | string | — | The controlled active tab value. |
onValueChange | (value: string, eventDetails: ChangeEventDetails) => void | — | Callback fired when the active tab changes. |
disabled | boolean | false | Whether all tabs are disabled. |
className | string | — | Additional classes for the root. |
URL State Props
| Prop | Type | Default | Description |
|---|---|---|---|
paramName | string | — | URL parameter name for syncing the active tab. |
paramValue | string | — | Controlled URL-state value. |
onUrlValueChange | (value: string) => void | — | Callback when the URL parameter value changes. |
paramClearOnDefault | boolean | true | Remove the URL parameter when it matches the default value. |
paramDebounce | number | — | Debounce URL updates in milliseconds. |
paramThrottle | number | — | Throttle URL updates in milliseconds. |
TabsList
Container for tab triggers.
| Prop | Type | Default | Description |
|---|---|---|---|
variant | "default" | "line" | "default" | Visual style. default uses the pill track; line uses an underline indicator. |
size | "sm" | "md" | "lg" | "md" | Trigger size. |
className | string | — | Additional classes for the list. |
TabsTrigger
Interactive tab trigger.
| Prop | Type | Default | Description |
|---|---|---|---|
value | string | — | The tab value. |
disabled | boolean | false | Whether the trigger is disabled. |
render | ReactElement | function | — | Render as a custom element while preserving tab behavior. |
nativeButton | boolean | true | Set to false when render outputs a non-button element. |
className | string | — | Additional classes for the trigger. |
TabsSeparator
Visual separator for grouped default tabs.
| Prop | Type | Description |
|---|---|---|
className | string | Additional classes for the separator. |
TabsContent
Tab panel content.
| Prop | Type | Description |
|---|---|---|
value | string | The tab value for the panel. |
className | string | Additional classes for the panel. |