Tabs
A set of layered sections of content displayed one at a time.
When to Use
Use Tabs when you need to:
- Organize related content into switchable sections within the same view
- Reduce visual clutter by showing only one content panel at a time
- Let users compare or switch between related data sets (e.g., Account vs. Password)
- Create settings pages with logically grouped options
- Display alternative views of the same content (e.g., Code vs. Preview)
When Not to Use
- Sequential steps or processes - use a Stepper or multi-step form instead
- Primary navigation between pages - use Navigation Menu or Sidebar
- Expandable/collapsible content sections - use Accordion
- Binary on/off choices - use Toggle Group or Switch
Default
Tabs with form content inside cards. The default variant uses a muted background container with rounded triggers.
Simple
Basic tabs with simple text content. Ideal for lightweight content switching.
With Icons
Tabs with leading icons in the triggers. Icons help users identify tabs at a glance.
Preview content
Disabled
Tabs with disabled triggers. Disabled tabs cannot be activated and are visually dimmed.
This tab is active and can be selected.
Full Width
Tabs that expand to fill the available width. Each trigger grows equally using flex-1.
This is the overview content. View your key metrics and recent activity here.
Folder Variant
Tabs styled like browser or file folder tabs. The active tab uses the primary color for strong emphasis.
Documents
23 files, 4.2 MB
Underline Variant
Clean tabs without a container background, using only an underline indicator for the active tab.
Profile Settings
Manage your public profile information and how others see you.
Variants Comparison
Side-by-side comparison of all three tab variants: default, folder, and underline.
Default
Folder
Underline
UX & Design Guidelines
Visual Hierarchy
Use the default variant for standard content switching within cards or panels. Choose variant="folder" when you need strong visual emphasis with bg-primary on the active tab. Use variant="underline" for lightweight, minimal tab bars that blend into content-heavy layouts.
Spacing & Layout
Tabs include a default gap-2 between the tab list and content. For full-width layouts, apply className="w-full" to both Tabs and TabsList, with flex-1 on each trigger. Keep the number of tabs between 3 and 7 for optimal scannability.
Responsive Behavior
On mobile, consider using full-width tabs so triggers span the viewport. For many tabs, wrap the tab list in a horizontal ScrollArea to prevent overflow. Icons help reduce label length on smaller screens. The underline variant works especially well on mobile due to its minimal chrome.
Color & Contrast
The default variant uses bg-muted for the list container and bg-background for the active trigger, providing subtle contrast. The folder variant leverages bg-primary with text-primary-foreground for high-contrast active states. Disabled triggers reduce opacity to 50% while maintaining readability.
Accessibility
Keyboard Navigation
- Tab -- Move focus into the tab list, then to the active tab panel content
- ArrowLeft / ArrowRight -- Navigate between tab triggers (horizontal orientation)
- ArrowUp / ArrowDown -- Navigate between tab triggers (vertical orientation)
- Home -- Move focus to the first tab trigger
- End -- Move focus to the last tab trigger
- Enter or Space -- Activate the focused tab (when
activationMode="manual")
Screen Reader Support
- Built on Radix UI Tabs, which provides correct
role="tablist",role="tab", androle="tabpanel"semantics - Each trigger is automatically linked to its content via
aria-controlsandaria-labelledby - Active tab is announced via
aria-selected="true" - Disabled state is communicated via
disabledattribute on the trigger
Focus Management
Visible focus ring with focus-visible:ring-2 and ring-ring. In automatic activation mode, focus movement immediately activates the tab. In manual mode, focus and activation are separate, letting users review options before committing. Focus wraps cyclically through triggers.
Activation Modes
activationMode="automatic" (default) activates a tab as soon as it receives focus, following WAI-ARIA recommended behavior for fast switching. activationMode="manual" requires an explicit Enter or Space to activate, which is preferable when tab content is expensive to render.
ARIA Attributes
{/* Standard tabs with accessible labels */}
<Tabs defaultValue="account" aria-label="Account settings">
<TabsList>
<TabsTrigger value="account">Account</TabsTrigger>
<TabsTrigger value="password">Password</TabsTrigger>
</TabsList>
<TabsContent value="account">...</TabsContent>
<TabsContent value="password">...</TabsContent>
</Tabs>
{/* Controlled tabs with onValueChange */}
<Tabs
value={activeTab}
onValueChange={setActiveTab}
aria-label="Dashboard navigation"
>
<TabsList>
<TabsTrigger value="overview">Overview</TabsTrigger>
<TabsTrigger value="analytics">Analytics</TabsTrigger>
</TabsList>
<TabsContent value="overview">...</TabsContent>
<TabsContent value="analytics">...</TabsContent>
</Tabs>
{/* Manual activation mode */}
<Tabs defaultValue="tab1" activationMode="manual">
<TabsList>
<TabsTrigger value="tab1">Tab 1</TabsTrigger>
<TabsTrigger value="tab2">Tab 2</TabsTrigger>
</TabsList>
<TabsContent value="tab1">...</TabsContent>
<TabsContent value="tab2">...</TabsContent>
</Tabs>Related Components
Toggle Group
A group of toggle buttons for mutually exclusive or multi-select options.
Navigation Menu
A collection of links for navigating between pages and sections.
Menubar
A visually persistent menu common in desktop applications with dropdowns.
Accordion
A vertically stacked set of collapsible content sections.
API Reference
The Tabs component is composed of four parts. Each accepts its own props in addition to standard HTML attributes.
Tabs
Root container that manages tab state and context.
| Prop | Type | Default | Description |
|---|---|---|---|
| defaultValue | string | --- | The value of the tab that should be active when initially rendered. |
| value | string | --- | Controlled value of the active tab. |
| onValueChange | (value: string) => void | --- | Event handler called when the active tab changes. |
| orientation | "horizontal" | "vertical" | "horizontal" | The orientation of the tabs. |
| activationMode | "automatic" | "manual" | "automatic" | When "automatic", tabs activate on focus. When "manual", tabs activate on click/Enter. |
TabsList
Container for tab triggers. Controls the visual variant for all child triggers.
| Prop | Type | Default | Description |
|---|---|---|---|
| variant | "default" | "folder" | "underline" | "default" | The visual style variant of the tab list. Determines container and trigger styling. |
| className | string | --- | Additional CSS classes to apply to the tab list container. |
TabsTrigger
Button that activates its associated content panel.
| Prop | Type | Default | Description |
|---|---|---|---|
| value | string | --- | Unique value that associates the trigger with its content panel. |
| disabled | boolean | false | When true, prevents the tab from being activated and applies disabled styling. |
| className | string | --- | Additional CSS classes to apply to the tab trigger. |
TabsContent
Content panel displayed when its associated trigger is active.
| Prop | Type | Default | Description |
|---|---|---|---|
| value | string | --- | Unique value that associates the content panel with its trigger. |
| forceMount | boolean | --- | Force mount the content panel even when inactive. Useful with animation libraries. |
| className | string | --- | Additional CSS classes to apply to the content panel. |