Tabs
A set of layered sections of content—known as tab panels—that are displayed one at a time.
Made by imskyleenPowered by
Installation
Variants
Card
Use the card variant for tabs with a bordered card container.
Contained
Use the contained variant for tabs with a muted background container.
Underline
Use the underline variant for tabs with a bottom border indicator.
Sizes
Small
Use size="sm" for compact tabs.
Large
Use size="lg" for larger tabs.
Layout
Equal Layout
Use layout="equal" with columns to create equal-width tabs.
Full Layout
Use layout="full" to make tabs span the full width.
Gap
Use the gap prop to control spacing between tabs.
Combinations
Card with Underline
Combine card variant with underline TabsList.
Contained with Equal Layout
Combine contained variant with equal layout.
Combined with Toggle Group
This example demonstrates the proper relationship between tabs and toggle groups. Use tabs to navigate between distinct content areas, and toggle groups within each tab to filter or adjust that specific view's content.
Patterns
Vertical orientation
Disabled trigger with tooltip
Count badges
Icon-only triggers
When to use
Tabs function as a navigation bar positioned atop content, allowing users to switch between distinct content views. Each tab displays unique content specific to that tab, without duplication across tabs. When a user interacts with a tab, it triggers the display of new content in a fresh view.
Use tabs when:
- Navigating between different, self-contained content areas
- Each section has unique content specific to that context
- Content changes completely when switching tabs
- Users need to switch between parallel information hierarchies
Don't use tabs when:
- Filtering or adjusting a single content view (use Toggle Group/Segmented Control instead)
- Content is shared or filtered across different states
- You need to show/hide portions of the same dataset
Usage
<Tabs>
<TabsList>
<TabsTrigger value="tab1">Tab 1</TabsTrigger>
<TabsTrigger value="tab2">Tab 2</TabsTrigger>
</TabsList>
<TabsContents>
<TabsContent value="tab1">Tab 1 Content</TabsContent>
<TabsContent value="tab2">Tab 2 Content</TabsContent>
</TabsContents>
</Tabs>Underline Variant
<Tabs>
<TabsList variant="underline">
<TabsTrigger variant="underline" value="tab1">Tab 1</TabsTrigger>
<TabsTrigger variant="underline" value="tab2">Tab 2</TabsTrigger>
</TabsList>
<TabsContents>
<TabsContent value="tab1">Tab 1 Content</TabsContent>
<TabsContent value="tab2">Tab 2 Content</TabsContent>
</TabsContents>
</Tabs>Props
Animate UI Props
Tabs
Prop
Type
TabsList
Prop
Type
TabsTrigger
Prop
Type
TabsContent
Prop
Type
TabsContents
Prop
Type
Keyboard interactions
| Key | Action |
|---|---|
Tab into TabsList | Focus lands on the active tab. |
ArrowLeft / ArrowRight | Moves focus between tabs (horizontal orientation). |
ArrowUp / ArrowDown | Moves focus between tabs (vertical orientation). |
Home / End | Jumps to first / last tab. |
Space / Enter | Activates the focused tab (with activateOnFocus={false}). |
As Links
Pass a JSX element (or render function) to TabsTrigger's render prop to swap the rendered element while keeping
keyboard, data-state, and active-highlight behavior intact.
<TabsList>
<TabsTrigger render={<Link to="/overview" />} value="overview">
Overview
</TabsTrigger>
<TabsTrigger render={<Link to="/billing" />} value="billing">
Billing
</TabsTrigger>
</TabsList>Accessibility
TabsListcarriesrole="tablist", eachTabsTriggerisrole="tab"witharia-selected, and eachTabsPanelisrole="tabpanel"wired viaaria-controls/aria-labelledby.- Focus is roving inside
TabsList— only the active tab is in the tab order; the others are reachable via arrow keys. - Base UI activates tabs on focus by default; pass
activateOnFocus={false}onTabsif a tab triggers expensive work and should only activate on explicitEnter/Space. - Use the
underlinevariant sparingly when tabs live next to inline links — the underline can be mistaken for a link.
Credits
- We use Base UI for the tabs component.
- We take our inspiration from Shadcn UI for the tabs style.
- We use Animate UI from imskyleen for all the animations.
Recent changes
- patchv1.2.0Pin shipped dependency floors to the version we develop against. Registry items now declare ranges like `^5.1.9` (the actual installed version) instead of collapsing to `^5.0.0`, so consumers start on the known-tested b…#133
- patchv1.2.0Polish the Tabs active-indicator animation. The highlight now slides strictly along the tab strip's axis (left/right for horizontal tabs, up/down for vertical tabs) instead of drifting diagonally when tabs wrap onto mul…#126
- minorv1.1.0Theme docs refresh, readability pass on semantic foregrounds, and consumer-facing Base UI regression fixes.#121
- minorv1.0.0Post-Base-UI polish. Public API unchanged.#116
- majorv1.0.0Migrate every Radix-based primitive to `@base-ui/react@^1.4.0` (Base UI).#114