Tabs
Tabs is a navigation component that switches between related content panels. Three variants and four sizes adapt to a wide range of layouts.
Playground
Account settings content
<Tabs defaultValue="account">
<Tabs.List>
<Tabs.Trigger value="account">Account</Tabs.Trigger>
<Tabs.Trigger value="settings">Settings</Tabs.Trigger>
<Tabs.Trigger value="notifications">Notifications</Tabs.Trigger>
</Tabs.List>
<Tabs.Content value="account">
<p className="text-sm text-text-muted">Account settings content</p>
</Tabs.Content>
<Tabs.Content value="settings">
<p className="text-sm text-text-muted">General settings content</p>
</Tabs.Content>
<Tabs.Content value="notifications">
<p className="text-sm text-text-muted">Notification preferences</p>
</Tabs.Content>
</Tabs>Variants
line
Content for tab 1
<Tabs defaultValue="tab1">
<Tabs.List variant="line">
<Tabs.Trigger value="tab1">Tab 1</Tabs.Trigger>
<Tabs.Trigger value="tab2">Tab 2</Tabs.Trigger>
<Tabs.Trigger value="tab3">Tab 3</Tabs.Trigger>
</Tabs.List>
<Tabs.Content value="tab1">
<p className="text-sm text-text-muted">Content for tab 1</p>
</Tabs.Content>
<Tabs.Content value="tab2">
<p className="text-sm text-text-muted">Content for tab 2</p>
</Tabs.Content>
<Tabs.Content value="tab3">
<p className="text-sm text-text-muted">Content for tab 3</p>
</Tabs.Content>
</Tabs>enclosed
Content for tab 1
<Tabs defaultValue="tab1">
<Tabs.List variant="enclosed">
<Tabs.Trigger value="tab1">Tab 1</Tabs.Trigger>
<Tabs.Trigger value="tab2">Tab 2</Tabs.Trigger>
<Tabs.Trigger value="tab3">Tab 3</Tabs.Trigger>
</Tabs.List>
<Tabs.Content value="tab1">
<p className="text-sm text-text-muted">Content for tab 1</p>
</Tabs.Content>
<Tabs.Content value="tab2">
<p className="text-sm text-text-muted">Content for tab 2</p>
</Tabs.Content>
<Tabs.Content value="tab3">
<p className="text-sm text-text-muted">Content for tab 3</p>
</Tabs.Content>
</Tabs>pill
Content for tab 1
<Tabs defaultValue="tab1">
<Tabs.List variant="pill">
<Tabs.Trigger value="tab1">Tab 1</Tabs.Trigger>
<Tabs.Trigger value="tab2">Tab 2</Tabs.Trigger>
<Tabs.Trigger value="tab3">Tab 3</Tabs.Trigger>
</Tabs.List>
<Tabs.Content value="tab1">
<p className="text-sm text-text-muted">Content for tab 1</p>
</Tabs.Content>
<Tabs.Content value="tab2">
<p className="text-sm text-text-muted">Content for tab 2</p>
</Tabs.Content>
<Tabs.Content value="tab3">
<p className="text-sm text-text-muted">Content for tab 3</p>
</Tabs.Content>
</Tabs>Sizes
smmddefaultlg| Size | Height | Font | Padding X | Preview |
|---|---|---|---|---|
sm | 32px | 13px | 12px | |
md | 36px | 13px | 14px | |
default | 40px | 14px | 16px | |
lg | 48px | 16px | 24px |
Features
Fitted
Account content
<Tabs defaultValue="tab1">
<Tabs.List fitted>
<Tabs.Trigger value="tab1">Account</Tabs.Trigger>
<Tabs.Trigger value="tab2">Settings</Tabs.Trigger>
<Tabs.Trigger value="tab3">Notifications</Tabs.Trigger>
</Tabs.List>
</Tabs>With Icons
Account settings
<Tabs defaultValue="account">
<Tabs.List>
<Tabs.Trigger value="account"><User /> Account</Tabs.Trigger>
<Tabs.Trigger value="settings"><Settings /> Settings</Tabs.Trigger>
<Tabs.Trigger value="notifications"><Bell /> Notifications</Tabs.Trigger>
</Tabs.List>
</Tabs>Disabled
Active tab content
<Tabs defaultValue="tab1">
<Tabs.List>
<Tabs.Trigger value="tab1">Active</Tabs.Trigger>
<Tabs.Trigger value="tab2" disabled>Disabled</Tabs.Trigger>
<Tabs.Trigger value="tab3">Active</Tabs.Trigger>
</Tabs.List>
</Tabs>API
Component Structure
Tabs— Radix Tabs.ListPropsTab bar — variant, size, color, radius, fitted.TriggerPropsTab button.ContentPropsTab panelProps
Tabs (Root)
defaultValueundefinedstringDefault selected tab value (uncontrolled)
valueundefinedstringSelected tab value (controlled)
onValueChangeundefined(value: string) => voidCallback fired on tab change
orientation"horizontal""horizontal" | "vertical"Orientation of the tab list
activationMode"automatic""automatic" | "manual"Tab activation mode — automatic switches on focus, manual requires Enter/Space
| Name | Type | Default | Description |
|---|---|---|---|
defaultValue | string | undefined | Default selected tab value (uncontrolled) |
value | string | undefined | Selected tab value (controlled) |
onValueChange | (value: string) => void | undefined | Callback fired on tab change |
orientation | "horizontal" | "vertical" | "horizontal" | Orientation of the tab list |
activationMode | "automatic" | "manual" | "automatic" | Tab activation mode — automatic switches on focus, manual requires Enter/Space |
Tabs.List
variant"line""line" | "enclosed" | "pill"Visual style of the tab list
size"default""sm" | "md" | "default" | "lg"Size of the tab triggers
color"default""default" | "primary"Active indicator color (line variant only)
radius"md""none" | "sm" | "base" | "md" | "lg" | "xl" | "2xl" | "3xl" | "full"Border radius — enclosed: top corners none–xl, pill: container 9 steps
fittedfalsebooleanDistribute tabs evenly across the full width
| Name | Type | Default | Description |
|---|---|---|---|
variant | "line" | "enclosed" | "pill" | "line" | Visual style of the tab list |
size | "sm" | "md" | "default" | "lg" | "default" | Size of the tab triggers |
color | "default" | "primary" | "default" | Active indicator color (line variant only) |
radius | "none" | "sm" | "base" | "md" | "lg" | "xl" | "2xl" | "3xl" | "full" | "md" | Border radius — enclosed: top corners none–xl, pill: container 9 steps |
fitted | boolean | false | Distribute tabs evenly across the full width |
Tabs.Trigger
value—stringUnique identifier for the tab (required)
disabledfalsebooleanDisable the tab
| Name | Type | Default | Description |
|---|---|---|---|
value | string | — | Unique identifier for the tab (required) |
disabled | boolean | false | Disable the tab |
Tabs.Content
value—stringMatching tab value (required)
forceMountundefinedbooleanKeep in DOM when inactive — for animations
| Name | Type | Default | Description |
|---|---|---|---|
value | string | — | Matching tab value (required) |
forceMount | boolean | undefined | Keep in DOM when inactive — for animations |
Anatomy
40px16pxmt-4Best Practices
Recommended
- ✓Keep tab labels short — one or two words
- ✓Use to group related content
- ✓Reinforce tab meaning with icons
- ✓Pre-select the most important tab by default
Don't
- ✗Don't exceed five tabs — limit to five or fewer
- ✗Don't use tabs for page-level navigation
- ✗Don't reorder tabs dynamically
- ✗Don't nest tabs within tabs
Accessibility
Keyboard
ARIA / WCAG
role="tablist"/role="tab"/role="tabpanel"- aria-selected reflects selection state automatically
- aria-orientation set automatically
- Disabled tabs are skipped in keyboard navigation
Tabs vs Segmented
Visually similar but different in purpose and structure — choose the right one.
Purpose
Tabs: Content navigation
Segmented: Value selection — filter, view toggle
Structure
Tabs: TabList + TabPanel combination
Segmented: Single component
Result
Tabs: Switch visible panels
Segmented: Change data in the same area
Placement
Tabs: Top of page or section
Segmented: Anywhere inside content
Radix Primitive
Tabs: @radix-ui/react-tabs
Segmented: RadioGroup
| Feature | Tabs | Segmented |
|---|---|---|
| Purpose | Content navigation | Value selection — filter, view toggle |
| Structure | TabList + TabPanel combination | Single component |
| Result | Switch visible panels | Change data in the same area |
| Placement | Top of page or section | Anywhere inside content |
| Radix Primitive | @radix-ui/react-tabs | RadioGroup |
Key distinction: Use Tabs when switching between different content panels. Use Segmented when changing what is displayed in the same content area. Even when they look similar (Tabs pill vs Segmented default), choose by whether Tabs.Content panels are present.