Tabs
A set of layered content panels (one shown at a time) switched by an accessible tab list.
Description
Tabs is a compound component (Tabs + TabsList + TabsTrigger + TabsContent) built on the Radix Tabs primitive. The list is a real role="tablist" of role="tab" buttons; each TabsContent is a role="tabpanel" linked to its trigger, and only the active panel is shown. Selecting a trigger swaps the visible panel in place.
Reach for it when each option reveals a content panel within the same surface (settings forms, a detail card with sub-views, an editor with modes). The triggers use the same line styling as TabMenu: a primary underline that slides to the active tab.
The free build ships the horizontal-line layout with a sliding bottom indicator. Pro unlocks the full set of layout variants (vertical-button, vertical-line, horizontal-line, horizontal-button) and indicator positions (left, top, bottom).
If your options instead navigate to routes or sections elsewhere on the page (no in-place panel), use TabMenu. It renders the tab list only and supports asChild links. For 2 to 5 inline, mutually exclusive options without rich item content, use SegmentedControl.
Installation
Anatomy
Tabs owns the selected value and the size context. TabsList wraps the triggers; each TabsTrigger is paired by value to a TabsContent panel.
Usage
Examples
Richer previews (the full set of layout variants and indicator positions) are marked with a Pro badge. The live demo still runs for everyone; the source needs a Pro seat.
Variants
The free build ships the horizontal-line layout. Pro unlocks vertical-button (a sliding pill), vertical-line (icon over label), and horizontal-button, so the tabs can match wherever they sit.
Indicators
The active tab is marked by a sliding line. The free build draws it on the bottom (shown above). Pro adds a top line and a vertical left rail for the button layouts.
Sizes
size on Tabs scales the triggers (sm, md default, and lg) and cascades to every TabsTrigger, so padding, type, and icon size scale together.
With Icon
Pass leading and/or trailing to a TabsTrigger. Icon size follows the active size, and the active tab's icon picks up the primary color.
Disabled
Set disabled on a TabsTrigger to dim it and skip it during arrow-key navigation.
Controlled
Pass value and onValueChange to drive selection from your own state. Reach for it when other UI needs to react to the active tab, or to persist it to the URL. Omit them (use defaultValue) for a simple uncontrolled switcher.
Accessibility
Built on the Radix Tabs primitive, so it follows the WAI-ARIA Tabs pattern: the list is role="tablist", triggers are role="tab" with aria-selected, and each panel is role="tabpanel" wired to its trigger via aria-controls / aria-labelledby. Focus uses a roving tabindex: one tab stop for the whole list, arrow keys move between tabs.
ARIA notes:
- Activation is automatic by default (focusing a tab selects it). Pass
activationMode="manual"onTabsto requireEnter/Space. - Disabled triggers are skipped by arrow-key navigation.
- If a trigger only shows an icon, add an
aria-labelso it announces its purpose.
Styling
Tailwind override: pass className to merge Tailwind classes with the component's CVA classes (via cn()).
Data slots and attributes: the component sets these for CSS targeting.
data-slot="tabs"on the root,data-slot="tabs-list"on the list,data-slot="tabs-trigger"on each trigger,data-slot="tabs-content"on each panel.data-slot="tabs-active-line"on the sliding active indicator;data-slot="tabs-trigger-label"on the label;data-slot="tabs-trigger-icon"(withdata-position="leading" | "trailing") on each icon.data-size="<size>"on the root and each trigger.- Radix sets
data-state="active" | "inactive"on the relevant elements.
Target the active trigger in CSS:
Related Components
- TabMenu: use this when the options navigate (routes or in-page sections) instead of swapping a panel in place; supports
asChildlinks. - SegmentedControl: use this for 2 to 5 inline mutually exclusive options without rich item content.
- Accordion: use this to expand multiple stacked regions at once rather than one panel at a time.
API Reference
Tabs
Root that owns selection state and the size context. Wraps Radix Tabs.Root, so its props (dir, activationMode, etc.) are accepted.
Props
TabsList
Wraps Radix Tabs.List. Renders role="tablist" and the baseline border.
TabsTrigger
Wraps Radix Tabs.Trigger. Renders role="tab".
Props
TabsContent
Wraps Radix Tabs.Content. Renders role="tabpanel"; only the panel whose value matches the active tab is shown.