Tabs

Panel switcher with pill, line, and segment variants. Prefer Content Switcher when you only switch mode without tab panels.

Also known as: tab bar, tab panels, tabbed panels, panel tabs

Installation

Install with the CLI, or copy the component source into your project.

Add tabs (npm)

npx --yes -p @default-file/ui df-ui add tabs

Default

The standard tab style uses a soft track with an animated active indicator.

Line

Underline indicators for docs and content chrome. By default, the divider only spans the tab labels. The second example stretches the divider across the full width.

Line align

Stretch the underline across the full width. Align to the start for tabs on the left, or to the end for tabs on the right.

Segment

Equal width mode switcher with a sliding active chip. Used in Color Picker for Hex, RGB, HSL, and HSB.

Vertical

Stack triggers in a column. Works with every variant: pill, line, and segment. Arrow keys move Up and Down, and the vertical pill track softens its default radius so the column reads as a rounded panel rather than a capsule.

Vertical with panels

In a vertical layout, the list sits to the left and the active panel fills the space beside it. This is a common settings pattern.

Account settings panel.

Vertical icons, badge, and disabled

Leading icons, trailing count badges, and disabled triggers work the same in vertical orientation, on both pill and line.

Line side

Choose which edge carries the divider and active indicator. In a vertical layout, use left or right (right by default). In a horizontal layout, use top or bottom (bottom by default). Prefer left when the list sits to the right of its content so the line faces the panel.

Icons, badge, and disabled

Leading icons, trailing count badges, and disabled triggers on pill and segment.

Gap and spacing

Control the space inside a trigger between icon, label, and badge, and the space between triggers. Both use design-scale units from the shared spacing scale (none or 0 through 200).

Sizes

Small, default, and large tabs.

Radius

Corner radius for the track and sliding chip. Pill defaults to full; segment defaults to lg.

Properties

Panel switcher with pill, line, and segment variants in horizontal or vertical orientation. Label ink is optically centered to cap height with text-box when available, and a 1cap line box otherwise. Compose Tabs, TabsList, TabsTrigger, and TabsContent.

Tabs

PropTypeDefaultNotes
variant"pill" | "line" | "segment""pill"Visual style. pill = soft rounded track; line = underline; segment = equal width mode switcher with a sliding chip (e.g. color input modes).
size"sm" | "default" | "lg""default"Trigger height and type size.
orientation"horizontal" | "vertical""horizontal"Layout axis. horizontal puts triggers in a row with the panel below; vertical stacks triggers in a column with the panel alongside. Arrow key navigation switches to Up/Down.
lineSide"top" | "bottom" | "left" | "right""bottom" (horizontal) / "right" (vertical)For the line variant only: which edge holds the divider and active indicator. Horizontal layouts accept top or bottom; vertical layouts accept left or right. Prefer left when the list sits to the right of its content so the line faces the panel.
lineAlign"start" | "end"-For the line variant only. Leave unset so the list sizes to its triggers. Choose start or end to stretch the divider across the available width and group the tabs on that side. In a horizontal layout, start places tabs on the left and end places them on the right. In a vertical layout, start places tabs at the top and end places them at the bottom.
radius"none" | "sm" | "md" | "lg" | "xl" | "2xl" | "full"-Corner radius for the track, sliding chip, and triggers. Defaults: pill full (2xl when vertical), segment lg. Line ignores radius.
cornerShape"round" | "smooth"-Corner curve for pill and segment chrome. Omit to inherit --df-corner-shape from the theme.
gapnumber | "none"1.5Gap inside each trigger between leading icon, label, and trailing badge. Design-scale units from the shared spacing scale (none/0, even integers through 200, half-steps like 0.5 and 1.5). One unit = 0.25rem via --spacing-unit.
spacingnumber | "none"0 (pill/line) / 0.5 (segment)Gap between triggers in the list. Same design-scale units as gap. Defaults keep pill and line flush and segment slightly open.
valuestring-Controlled active tab value.
defaultValuestring-Uncontrolled initial tab value.
onValueChange(value: string) => void-Called when the active tab changes.
classNamestring-Additional styles on the root.

TabsList

Container for triggers. Inherits variant, size, and radius from Tabs. Hosts the animated active indicator.

PropTypeDefaultNotes
classNamestring-Additional styles on the list.
childrenReactNode-TabsTrigger children.

TabsTrigger

PropTypeDefaultNotes
valuestring-Tab value this trigger activates (required).
leadingReactNode-Icon or node before the label.
trailingReactNode-Node after the label. Pass a Badge with a count for notifications.
disabledboolean-Non-interactive trigger. Skipped by pointer and selection.
childrenReactNode-Trigger label.

TabsContent

Selected panels are focusable (tabIndex 0). Inactive panels omit the tab stop unless forceMount keeps them mounted with tabIndex unset.

PropTypeDefaultNotes
valuestring-Shows when this value is active (required).
forceMountbooleanfalseKeep content mounted when inactive.
childrenReactNode-Panel content.
classNamestring-Additional styles on the panel.

Segment variant

Equal width segmented control for compact mode switching. The active chip slides between options with transform animation. Animated indicator (built-in): TabsList renders a sliding background chip behind the active trigger. Honors prefers-reduced-motion.

Tokens

Theme defaults live on :root. Override these globally or on a local host.

TokenTypeDefaultNotes
--df-tabs-indicator-thicknessCSS lengthvar(--border-width-thick)Line variant indicator thickness.
--df-shadow-tabs-indicatorCSS shadow0 1px 2px color-mix(in oklch, var(--foreground) var(--df-shadow-intensity-lg), transparent)Shadow under the sliding indicator.
--df-tabs-gapCSS length-Instance variable set by the gap prop. Sizes the gap between leading icon, label, and trailing badge inside a trigger.
--df-tabs-spacingCSS length-Instance variable set by the spacing prop. Sizes the gap between triggers in the list.
--df-tabs-panel-gapCSS length-Instance variable set between the list and its panel.
--mutedCSS colorvar(--df-neutral-50)Pill variant track fill.
--backgroundCSS colorvar(--df-neutral-0)Active trigger and sliding chip fill.
--foregroundCSS colorvar(--df-neutral-900)Active trigger label.
--borderCSS colorvar(--df-neutral-100)Line variant divider.
--df-corner-shapeCSS corner-shapevar(--df-corner-shape-round)Theme corner curve for all kit chrome. round = circular arcs; smooth = continuous squircle. Set with df-ui init --corner-shape, or override on :root. Default round.
--df-label-line-heightCSS line-heightvar(--df-leading-none)Line box for label flex centering. Defaults to --df-leading-none. When text-box is unavailable and the cap unit is supported, the kit sets this to 1cap so flex centering matches cap-height ink.