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
bunx @gridland/demo tabscurl -fsSL https://raw.githubusercontent.com/thoughtfulllc/gridland/main/scripts/run-demo.sh | bash -s tabsInstallation
bunx shadcn@latest add @gridland/tab-barUsage
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.
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.
<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.
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.
<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.
<Tabs defaultValue="a">
<TabsList separator={false}>
<TabsTrigger value="a">Tab A</TabsTrigger>
<TabsTrigger value="b">Tab B</TabsTrigger>
</TabsList>
</Tabs>Compound Components
| Component | Description |
|---|---|
Tabs | Root container with active tab state |
TabsList | Horizontal tab bar built from TabsTrigger children |
TabsTrigger | Declares a tab option. Does not render on its own — TabsList reads its props. |
TabsContent | Renders its children only when its value matches the active tab |
TabBar | Simple convenience wrapper (no content panels) |
API Reference
Tabs
| Prop | Type | Default | Description |
|---|---|---|---|
value | string | - | Controlled active tab value |
defaultValue | string | "" | Default active tab (uncontrolled) |
onValueChange | (value: string) => void | - | Called when the active tab changes |
children | ReactNode | - | Sub-components |
TabsList
| Prop | Type | Default | Description |
|---|---|---|---|
label | string | - | Text label shown before the triggers |
focused | boolean | true | Whether the tab bar appears focused |
activeColor | string | theme.accent | Foreground color of the active trigger |
separator | boolean | true | Show horizontal separator below triggers |
children | ReactNode | - | TabsTrigger components |
TabsTrigger
| Prop | Type | Description |
|---|---|---|
value | string | Unique value linking this trigger to its TabsContent |
children | ReactNode | Label text displayed in the tab bar |
TabsContent
| Prop | Type | Description |
|---|---|---|
value | string | Must match the active tab value to render |
children | ReactNode | Content shown when this tab is active |
TabBar
| Prop | Type | Default | Description |
|---|---|---|---|
label | string | - | Text label shown before the options |
options | string[] | - | Array of option strings to display |
selectedIndex | number | - | Zero-based index of the selected option |
focused | boolean | true | Whether the tab bar appears focused |
activeColor | string | theme.accent | Foreground color of the selected option |
separator | boolean | true | Show horizontal separator below tabs |