Skip to main content

Tabs

StorybookView in Storybook

Explore interactive examples and all component variations in our Storybook.

The Tabs component organizes content into multiple panels with accessible keyboard navigation, focus management, and customizable sizing. Supports two visual variants — the default pill style and an outline file-tab style — as well as controlled and uncontrolled modes.

Basic Usage

Overview content

Sizes

Pass the same size to both TabsList and each TabsTrigger. Available sizes: sm, md (default), lg, xl.

sm

md

lg

xl

With Icons

Place a Lucide icon before the label inside TabsTrigger. The trigger handles spacing automatically.

Public Profile

Update your photo and personal details.

Outline Variant

Set variant="outline" on the Tabs root for a file-tab appearance — an underline connects the list to the content area, and the active tab appears raised above it. Ideal for code editors, document viewers, or any multi-panel interface that should feel like open files.

'use client'
import { cn } from '@/lib/utils'

Collapse Label

Add collapseLabel to a TabsTrigger to show only the icon when that tab is inactive. The label reappears when the tab becomes active. This keeps the tab bar compact while still surfacing context on selection. The label remains accessible to screen readers at all times.

Overview

collapseLabel works with both variants and can be mixed — some tabs collapse while others always show their label:

Notifications panel

Controlled

Pass value and onValueChange to control the active tab from outside:

Active:
profile
Profile panel

Properties

Tabs

PropertyTypeDefaultDescription
defaultValuestringInitial active tab (uncontrolled).
valuestringActive tab value (controlled).
onValueChange(value: string) => voidCallback fired when the active tab changes.
variant"default" | "outline""default"Visual style. default is a pill/segmented control; outline looks like file tabs.
orientation"horizontal" | "vertical""horizontal"Layout direction of the tab list.
dir"ltr" | "rtl"Reading direction.
activationMode"automatic" | "manual""automatic"Whether focus automatically activates a tab.
classNamestringAdditional CSS classes.

TabsList

PropertyTypeDefaultDescription
size"sm" | "md" | "lg" | "xl""md"Height of the tab list.
loopbooleantrueWhether arrow-key navigation wraps around.
classNamestringAdditional CSS classes.

TabsTrigger

PropertyTypeDefaultDescription
valuestringRequired. Unique identifier linking this trigger to its content panel.
size"sm" | "md" | "lg" | "xl""md"Size of the trigger. Should match the TabsList size.
collapseLabelbooleanfalseWhen true, hides the text label when the tab is inactive, showing only the icon. Requires an icon as the first child. The label remains visible to screen readers.
disabledbooleanfalsePrevents selection and keyboard navigation.
classNamestringAdditional CSS classes.

TabsContent

PropertyTypeDefaultDescription
valuestringRequired. Matches the corresponding TabsTrigger value.
forceMountbooleanfalseKeep the panel in the DOM even when inactive (useful for animating exit).
classNamestringAdditional CSS classes.

Accessibility

  • Keyboard navigation/ (or / for vertical) move between tabs; Home/End jump to first/last. Focus loops by default.
  • Roving tabindex — only the active tab is in the natural tab sequence; inactive tabs are reachable via arrow keys.
  • ARIArole="tablist", role="tab", role="tabpanel", aria-selected, aria-controls, and aria-labelledby are set automatically.
  • collapseLabel — collapsed labels use sr-only so screen readers still announce the full tab name.