Skip to main content

Basics

Tabs

Organize related content into switchable panels with simple or advanced API, icons, and disabled states.

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

PropTypeDefaultDescription
defaultValuestringfirst non-disabled tabInitially active tab value (slugified title or trigger value)
defaultTabIndexnumberSelect the initially active tab by numeric index (0-based) instead of by value
syncbooleantrueSync active tab with matching Tabs/CodeGroups on the page
borderBottombooleantrueShow the bottom border line under the tab bar

Tab (simple API)

PropTypeRequiredDescription
titlestringYesTab label shown in the tab bar
iconstringNoLucide icon name (or emoji)
iconTypestringNoFont Awesome style, when the icon comes from that library
idstringNoCustom id for anchor-linking this tab (defaults to the title)
disabledbooleanNoMark the tab as unclickable

TabsList (compound API)

PropTypeDescription
childrenReactNodeOne or more <TabsTrigger>

TabsTrigger (compound API)

PropTypeRequiredDescription
valuestringYesIdentifier — must match a <TabsContent> value
iconstringNoLucide icon name (or emoji)
iconTypestringNoFont Awesome style, when the icon comes from that library
idstringNoCustom id for anchor-linking this tab (defaults to the title)
disabledbooleanNoMark the tab as unclickable

TabsContent (compound API)

PropTypeRequiredDescription
valuestringYesIdentifier — must match a <TabsTrigger> value
Was this page helpful?

Last updated August 10, 2026

Tabs | NookDocs | NookDocs