Tabs
A track cut on the slant at both ends, and a slab of the accent that springs to the active tab. Every edge leans the same way, so at either end the slab sits parallel to the track.
Install
# once per project: where @zeroui items come frompnpm dlx shadcn@latest registry add @zeroui=https://zeroui.catforest.dev/r/{name}.jsonpnpm dlx shadcn@latest add @zeroui/tabsExamples
With panels
import { Tabs, TabsList, TabsPanel, TabsTab } from "@/components/zero/tabs";export default function TabsBasic() { return ( <Tabs defaultValue="today" className="w-full max-w-md"> <TabsList> <TabsTab value="today">Today</TabsTab> <TabsTab value="week">This week</TabsTab> <TabsTab value="later">Later</TabsTab> </TabsList> <TabsPanel value="today" className="font-medium text-zero-text-2"> Three errands, one delivery across the river, a call at nine. </TabsPanel> <TabsPanel value="week" className="font-medium text-zero-text-2"> The workshop reopens on Thursday; the parts arrive the day before. </TabsPanel> <TabsPanel value="later" className="font-medium text-zero-text-2"> Nothing planned yet. </TabsPanel> </Tabs> );}Sizes
import { Tabs, TabsList, TabsTab } from "@/components/zero/tabs";export default function TabsSizes() { return ( <div className="grid justify-items-center gap-5"> {(["sm", "md", "lg"] as const).map((size) => ( <Tabs key={size} size={size} defaultValue="notes"> <TabsList> <TabsTab value="notes">Notes</TabsTab> <TabsTab value="level">Level</TabsTab> <TabsTab value="schedule">Schedule</TabsTab> </TabsList> </Tabs> ))} </div> );}Icons, long labels, a disabled tab
import { LockIcon, SearchIcon } from "@/components/zero/icons";import { Tabs, TabsList, TabsTab } from "@/components/zero/tabs";export default function TabsIcons() { return ( <Tabs defaultValue="all"> <TabsList> <TabsTab value="all">All</TabsTab> <TabsTab value="open">Open commissions</TabsTab> <TabsTab value="search"> <SearchIcon /> Find </TabsTab> <TabsTab value="locked" disabled> <LockIcon /> Locked </TabsTab> </TabsList> </Tabs> );}Behaviour
The slab springs to the new tab and settles in about a quarter of a second; under reduced motion it lands without travelling. While it slides, the part of each label over it turns dark and the rest stays light, so no label is ever dark on the dark track.
Arrow keys move focus along the tabs; Enter or Space activates the focused one, which then fills itself straight away inside the selection frame. Tabs are horizontal only.
Props
Tabs
| Prop | Type | Default | Description |
|---|---|---|---|
| size | "sm" | "md" | "lg" | "md" | A tab is 32, 40 or 52 px tall; the track adds its outline and inset. |
Also takes every prop of Base UI's Tabs.Root.
TabsList
Also takes every prop of Base UI's Tabs.List.
TabsTab
| Prop | Type | Default | Description |
|---|---|---|---|
| value | string | — | Which panel this tab shows. |
Also takes every prop of Base UI's Tabs.Tab.
TabsPanel
| Prop | Type | Default | Description |
|---|---|---|---|
| value | string | — | The tab that shows this panel. |
Also takes every prop of Base UI's Tabs.Panel.