gridland
Components

Tabs

A compound tab component with triggers and content panels

A compound tab component. Declare triggers and content panels side by side — the active panel renders automatically.

TabBar
?

Run demo

Terminal
bunx @gridland/demo tabs
Terminal
curl -fsSL https://raw.githubusercontent.com/thoughtfulllc/gridland/main/scripts/run-demo.sh | bash -s tabs

Installation

bunx shadcn@latest add @gridland/tab-bar

Usage

import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tab-bar"
<Tabs defaultValue="files">
  <TabsList>
    <TabsTrigger value="files">Files</TabsTrigger>
    <TabsTrigger value="search">Search</TabsTrigger>
    <TabsTrigger value="git">Git</TabsTrigger>
  </TabsList>
  <TabsContent value="files">
    <text>Browse project files</text>
  </TabsContent>
  <TabsContent value="search">
    <text>Search across files</text>
  </TabsContent>
  <TabsContent value="git">
    <text>View git status</text>
  </TabsContent>
</Tabs>

Examples

Full Example

Tabs – with content
?

Simple API

For cases where you don't need content panels, use the TabBar convenience wrapper.

Simple API
import { TabBar } from "@/components/ui/tab-bar"

<TabBar label="View" options={["Files", "Search", "Git"]} selectedIndex={0} />

With Label

Show a text label before the triggers.

With label
<Tabs defaultValue="code">
  <TabsList label="Language">
    <TabsTrigger value="code">Code</TabsTrigger>
    <TabsTrigger value="preview">Preview</TabsTrigger>
  </TabsList>
  <TabsContent value="code">
    <text>Source code</text>
  </TabsContent>
  <TabsContent value="preview">
    <text>Live preview</text>
  </TabsContent>
</Tabs>

Controlled

Use value and onValueChange to control the active tab externally.

Controlled
const [tab, setTab] = useState("files")

<Tabs value={tab} onValueChange={setTab}>
  <TabsList>
    <TabsTrigger value="files">Files</TabsTrigger>
    <TabsTrigger value="search">Search</TabsTrigger>
  </TabsList>
  <TabsContent value="files">
    <text>Files panel</text>
  </TabsContent>
  <TabsContent value="search">
    <text>Search panel</text>
  </TabsContent>
</Tabs>

Unfocused

Set focused={false} on TabsList to render in a dimmed, unfocused style.

Unfocused
<Tabs defaultValue="a">
  <TabsList focused={false}>
    <TabsTrigger value="a">Tab A</TabsTrigger>
    <TabsTrigger value="b">Tab B</TabsTrigger>
  </TabsList>
</Tabs>

No Separator

Hide the horizontal separator line below the tab bar.

No separator
<Tabs defaultValue="a">
  <TabsList separator={false}>
    <TabsTrigger value="a">Tab A</TabsTrigger>
    <TabsTrigger value="b">Tab B</TabsTrigger>
  </TabsList>
</Tabs>

Compound Components

ComponentDescription
TabsRoot container with active tab state
TabsListHorizontal tab bar built from TabsTrigger children
TabsTriggerDeclares a tab option. Does not render on its own — TabsList reads its props.
TabsContentRenders its children only when its value matches the active tab
TabBarSimple convenience wrapper (no content panels)

API Reference

Tabs

PropTypeDefaultDescription
valuestring-Controlled active tab value
defaultValuestring""Default active tab (uncontrolled)
onValueChange(value: string) => void-Called when the active tab changes
childrenReactNode-Sub-components

TabsList

PropTypeDefaultDescription
labelstring-Text label shown before the triggers
focusedbooleantrueWhether the tab bar appears focused
activeColorstringtheme.accentForeground color of the active trigger
separatorbooleantrueShow horizontal separator below triggers
childrenReactNode-TabsTrigger components

TabsTrigger

PropTypeDescription
valuestringUnique value linking this trigger to its TabsContent
childrenReactNodeLabel text displayed in the tab bar

TabsContent

PropTypeDescription
valuestringMust match the active tab value to render
childrenReactNodeContent shown when this tab is active

TabBar

PropTypeDefaultDescription
labelstring-Text label shown before the options
optionsstring[]-Array of option strings to display
selectedIndexnumber-Zero-based index of the selected option
focusedbooleantrueWhether the tab bar appears focused
activeColorstringtheme.accentForeground color of the selected option
separatorbooleantrueShow horizontal separator below tabs