Basic usage
The simplest way to create tabs. Each <Tab> becomes a panel with its title as the tab label:
<Tabs>
<Tab title="React">
React uses JSX for templating.
</Tab>
<Tab title="Vue">
Vue uses single-file components with template syntax.
</Tab>
<Tab title="Svelte">
Svelte compiles components at build time.
</Tab>
</Tabs>Tab icons
Add a Lucide icon with the icon prop:
<Tabs>
<Tab title="macOS" icon="cpu">
Install via Homebrew: `brew install nookdocs`
</Tab>
<Tab title="Linux" icon="terminal">
Install via apt or yum.
</Tab>
<Tab title="Windows" icon="package">
Install via Chocolatey or winget.
</Tab>
</Tabs>Default tab
Set defaultValue on the parent <Tabs> to pick the initially active tab. The value is the slugified title (lowercase, hyphens). If omitted, the first non-disabled tab is active.
<Tabs defaultValue="vue">
<Tab title="React">React content</Tab>
<Tab title="Vue">Vue content (active by default)</Tab>
</Tabs>Disabled tabs
Mark a tab as disabled for "coming soon" content:
<Tabs>
<Tab title="REST API">REST is GA today.</Tab>
<Tab title="GraphQL">GraphQL is GA today.</Tab>
<Tab title="gRPC" disabled>gRPC is in private beta.</Tab>
</Tabs>Advanced API
For more control (custom value identifiers, separate trigger/content layout), use the compound API with TabsList, TabsTrigger, and TabsContent:
<Tabs>
<TabsList>
<TabsTrigger value="rest">REST API</TabsTrigger>
<TabsTrigger value="graphql">GraphQL</TabsTrigger>
<TabsTrigger value="grpc" disabled>gRPC (soon)</TabsTrigger>
</TabsList>
<TabsContent value="rest">REST is GA today.</TabsContent>
<TabsContent value="graphql">GraphQL is GA today.</TabsContent>
<TabsContent value="grpc">gRPC is in private beta.</TabsContent>
</Tabs>Tab sync
Tabs with matching labels automatically sync across the page. Click "npm" in one tab group, and all other Tabs and CodeGroups with an "npm" tab switch too. Selections persist across page navigations via localStorage.
Disable sync on a specific tab group with sync={false}:
<Tabs sync={false}>
<Tab title="Option A">Independent — not synced</Tab>
<Tab title="Option B">This tab group stands alone</Tab>
</Tabs>Default tab by index
When you don't have a stable value to reference, select the initial tab by its position using defaultTabIndex (0-based):
<Tabs defaultTabIndex={1}>
<Tab title="First">This is not active.</Tab>
<Tab title="Second">This tab opens by default.</Tab>
</Tabs>If both defaultValue and defaultTabIndex are set, defaultValue takes priority.
Hide bottom border
Set borderBottom={false} to remove the line under the tab bar. Useful when embedding tabs inside another bordered container where the extra line adds visual noise:
<Tabs borderBottom={false}>
<Tab title="Preview">Content without the underline border.</Tab>
<Tab title="Code">Source code view.</Tab>
</Tabs>Differences from CodeGroup
For code-only switching (like the same install command in npm/yarn/pnpm), use <CodeGroup> instead. It's shorter, the tab bar is styled like a code block header, and the active tab inherits the code block syntax highlighting.
<Tabs> is for mixed content — prose, images, components, or anything that isn't just code.
Props
Tabs
| Prop | Type | Default | Description |
defaultValue | string | first non-disabled tab | Initially active tab value (slugified title or trigger value) |
defaultTabIndex | number | — | Select the initially active tab by numeric index (0-based) instead of by value |
sync | boolean | true | Sync active tab with matching Tabs/CodeGroups on the page |
borderBottom | boolean | true | Show the bottom border line under the tab bar |
Tab (simple API)
| Prop | Type | Required | Description |
title | string | Yes | Tab label shown in the tab bar |
icon | string | No | Lucide icon name (or emoji) |
iconType | string | No | Font Awesome style, when the icon comes from that library |
id | string | No | Custom id for anchor-linking this tab (defaults to the title) |
disabled | boolean | No | Mark the tab as unclickable |
TabsList (compound API)
| Prop | Type | Description |
children | ReactNode | One or more <TabsTrigger> |
TabsTrigger (compound API)
| Prop | Type | Required | Description |
value | string | Yes | Identifier — must match a <TabsContent> value |
icon | string | No | Lucide icon name (or emoji) |
iconType | string | No | Font Awesome style, when the icon comes from that library |
id | string | No | Custom id for anchor-linking this tab (defaults to the title) |
disabled | boolean | No | Mark the tab as unclickable |
TabsContent (compound API)
| Prop | Type | Required | Description |
value | string | Yes | Identifier — must match a <TabsTrigger> value |