Skip to content

Tabs

Stable

Switches between related views that share a context, showing one panel at a time without leaving the page.

Project overview

12 open issues, 3 pull requests awaiting review, last deploy 18 minutes ago.

Anatomy

Project overview
  1. 1ListThe rail that holds the tabs: a segmented control by default, a hairline with variant="line".
  2. 2TriggerA tab. A short noun label, with an optional leading icon.
  3. 3IndicatorA single element that slides to the active tab.
  4. 4PanelThe content of the active tab. Focusable, so keyboard users can reach it.

Installation

$ pnpm dlx shadcn@latest add https://www.prfct.dev/r/tabs.json

Usage

import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
<Tabs defaultValue="account">
  <TabsList>
    <TabsTrigger value="account">Account</TabsTrigger>
    <TabsTrigger value="password">Password</TabsTrigger>
  </TabsList>
  <TabsContent value="account">Account settings.</TabsContent>
  <TabsContent value="password">Password settings.</TabsContent>
</Tabs>

Every TabsTrigger must live inside TabsList, and each TabsContent pairs with the trigger of the same value. The list renders its own indicator: a single element that glides to the active tab using Base UI's measured position, instead of every tab fading its own background.

Examples

Segmented

The default variant is a segmented control — the active tab rides on a raised pill inside a muted rail. Use it for compact view switches and for tabs inside cards, toolbars and dialogs.

Project overview

12 open issues, 3 pull requests awaiting review, last deploy 18 minutes ago.

Line

variant="line" draws a hairline rail with a sliding underline. Use it for page-level sections, where tabs act as a secondary navigation bar under the page title.

Traffic is up 12% week over week, driven by organic search.

Vertical

Set orientation="vertical" for settings pages and long lists of sections. Arrow keys switch to and automatically.

General

Workspace name, URL and default language.

With icons

Icons help people scan tabs that represent layouts or content types. Keep the text label — an icon alone is rarely unambiguous.

Disabled

Disable a tab when its view exists but is unavailable, and say why — a short badge or tooltip. Base UI skips disabled tabs during keyboard navigation.

Browse files, branches and commits.

Controlled

Control value when something other than the tabs changes the view — here a stepper's Continue button.

Name your project and choose a region.

Guidelines

When to use

  • To organize related content of equal importance that people switch between, without needing to compare it side by side.
  • To split long settings or detail pages into sections that share one header and context.

When not to use

  • For sequential steps that must be completed in order — use a stepper with explicit Back and Continue, or a single scrolling form.
  • For content people need to compare — show it side by side.
  • For navigation between pages — tabs switch views in place; links belong in a Navigation Menu or Sidebar.
  • For two to five options that set a value — use a Toggle Group.

Labels

Use short, specific nouns in sentence case — one or two words each. Labels must describe their panel so people can predict what they'll see: Members, not More. Don't wrap tab labels onto two lines; if they don't fit, there are too many tabs.

Do.Short, parallel labels that predict their content.
Don’t.Long, inconsistent labels make the rail hard to scan.

Choosing a variant

Pick one variant per surface and stick with it. line belongs to the page chrome; the segmented default belongs inside components. Never nest one set of tabs in another's panel — it creates two competing places for "where am I".

State and URLs

When tabs represent sections of a page people might share or return to, store the active tab in the URL (for example, ?tab=billing) and control value from it. Keep panels mounted with keepMounted only when their state must survive switching.

Accessibility

Tabs implement the WAI-ARIA tabs pattern: a tablist of tabs, each controlling a tabpanel. The list is a single tab stop with roving focus.

KeyBehavior
Tab
Moves focus to the active tab, then into the active panel.
In horizontal tabs, moves focus to the previous or next tab. Focus wraps around.
In vertical tabs, moves focus to the previous or next tab.
HomeEnd
Moves focus to the first or last tab.
EnterSpace
Activates the focused tab (when activateOnFocus is off).
  • Manual activation is the default: arrow keys move focus, Enter or Space switches the panel. Set activateOnFocus on TabsList when panels are cheap to render, so focus and selection move together.
  • Panels are focusable so keyboard users can reach content that has no interactive elements; they show a focus ring when reached with Tab.
  • Label the list with aria-label when there is no visible heading that describes the tabs.

API reference

Tabs

The root. Accepts every prop of the Base UI Tabs.Root.

PropTypeDefault
value

Controlled value of the active tab.

anyNo default
defaultValue

Initially active tab when uncontrolled.

any0
onValueChange

Called when the active tab changes.

(value: any, details) => voidNo default
orientation

Layout of the list and direction of arrow-key navigation.

"horizontal" | "vertical""horizontal"

TabsList

PropTypeDefault
variant

Segmented control or underlined rail.

"default" | "line""default"
activateOnFocus

Activate tabs as arrow keys move focus.

booleanfalse
loopFocus

Wrap focus from the last tab to the first.

booleantrue

TabsTrigger

PropTypeDefault
valuerequired

Identifies the tab and its panel.

anyNo default
disabled

Prevents activation and skips the tab in keyboard navigation.

booleanfalse

TabsContent

PropTypeDefault
valuerequired

The tab value this panel belongs to.

anyNo default
keepMounted

Keep the panel in the DOM while hidden, preserving its state.

booleanfalse

tabsListVariants

The class generator for TabsList, exported for building custom lists that match.