1
ComponentsNavigation

Tabs

Equal-priority panels within one local page context, with horizontal and vertical orientation.

Purpose

Use Tabs for equal-priority panels within one local page context, such as settings sections or compact detail views.

Tabbed panels

Workspace health and recent usage.
import { Tabs, TabsList, TabsPanel, TabsTab } from "@/components/ui/tabs";

export function Example() {
  return (
    <Tabs defaultValue="overview">
      <TabsList><TabsTab value="overview">Overview</TabsTab></TabsList>
      <TabsPanel value="overview">Overview panel</TabsPanel>
    </Tabs>
  );
}

Installation

With the Siteplane registry alias configured, add the component and import the installed source from your app.

CLI

pnpm dlx shadcn@4.16.1 add @siteplane/tabs

Import

import { Tabs, TabsList, TabsPanel, TabsTab } from "@/components/ui/tabs";
import { TabsContent, TabsTrigger } from "@/components/ui/tabs";

Need the machine-readable source metadata? View registry JSON.

Usage

Use Tabs to switch between related panels in the same context. Keep panel content mounted according to the primitive contract.

import { Tabs, TabsList, TabsPanel, TabsTab } from "@/components/ui/tabs";

export function Example() {
  return (
    <Tabs defaultValue="overview">
      <TabsList><TabsTab value="overview">Overview</TabsTab></TabsList>
      <TabsPanel value="overview">Overview panel</TabsPanel>
    </Tabs>
  );
}

Examples

Underline variant, vertical orientation, sizes, disabled tabs, icons and controlled selection are props and compositions of the same primitive.

Underline variant

Workspace health and recent usage.

<Tabs defaultValue="overview">
  <div className="border-b">
    <TabsList aria-label="Workspace sections" variant="underline">
      <TabsTab value="overview">Overview</TabsTab>
      <TabsTab value="activity">Activity</TabsTab>
      <TabsTab value="settings">Settings</TabsTab>
    </TabsList>
  </div>
  <TabsPanel value="overview">Workspace health and recent usage.</TabsPanel>
  <TabsPanel value="activity">Latest member activity.</TabsPanel>
  <TabsPanel value="settings">Workspace configuration.</TabsPanel>
</Tabs>

Vertical orientation

Workspace health and recent usage.

<Tabs defaultValue="overview" orientation="vertical">
  <TabsList aria-label="Workspace sections">
    <TabsTab value="overview">Overview</TabsTab>
    <TabsTab value="activity">Activity</TabsTab>
    <TabsTab value="settings">Settings</TabsTab>
  </TabsList>
  <TabsPanel value="overview">Workspace health and recent usage.</TabsPanel>
  <TabsPanel value="activity">Latest member activity.</TabsPanel>
  <TabsPanel value="settings">Workspace configuration.</TabsPanel>
</Tabs>

Sizes

<Tabs size="sm">...</Tabs>
<Tabs>...</Tabs>
<Tabs size="lg">...</Tabs>
<Tabs size="xl">...</Tabs>

Disabled tab

Workspace health and recent usage.

<TabsList aria-label="Workspace sections">
  <TabsTab value="overview">Overview</TabsTab>
  <TabsTab disabled value="billing">Billing</TabsTab>
  <TabsTab value="settings">Settings</TabsTab>
</TabsList>

With icons

Project activity, recent changes, and workspace events.

<TabsList aria-label="Monitoring sections">
  <TabsTab value="activity">
    <ActivityIcon aria-hidden="true" />
    Activity
  </TabsTab>
  <TabsTab value="security">
    <ShieldIcon aria-hidden="true" />
    Security
  </TabsTab>
  <TabsTab value="settings">
    <SettingsIcon aria-hidden="true" />
    Settings
  </TabsTab>
</TabsList>

Controlled tabs

Workspace health and recent usage.

Current tab: overview
const [value, setValue] = useState("overview");

<Tabs
  onValueChange={(nextValue) => setValue(String(nextValue ?? "overview"))}
  value={value}
>
  <TabsList aria-label="Workspace sections">
    <TabsTab value="overview">Overview</TabsTab>
    <TabsTab value="activity">Activity</TabsTab>
    <TabsTab value="settings">Settings</TabsTab>
  </TabsList>
  <TabsPanel value="overview">Workspace health and recent usage.</TabsPanel>
  <TabsPanel value="activity">Latest member activity.</TabsPanel>
  <TabsPanel value="settings">Workspace configuration.</TabsPanel>
</Tabs>

<span>Current tab: {value}</span>

Underline vertical

In vertical orientation the underline indicator becomes a side bar.

Workspace health and recent usage.

<Tabs defaultValue="overview" orientation="vertical">
  <div className="border-s">
    <TabsList aria-label="Workspace sections" variant="underline">
      <TabsTab value="overview">Overview</TabsTab>
      <TabsTab value="activity">Activity</TabsTab>
      <TabsTab value="settings">Settings</TabsTab>
    </TabsList>
  </div>
  <TabsPanel value="overview">Workspace health and recent usage.</TabsPanel>
  <TabsPanel value="activity">Latest member activity.</TabsPanel>
  <TabsPanel value="settings">Workspace configuration.</TabsPanel>
</Tabs>

Size overrides

TabsList and a single TabsTab accept their own size, overriding the root.

{/* Size on the list */}
<TabsList aria-label="Workspace sections" size="lg">...</TabsList>

{/* Size on a single tab */}
<TabsTab size="sm" value="activity">Activity</TabsTab>

API Reference

The reference lists the source-owned exports and props that are easy to miss in visual examples. Inherited Base UI props remain available unless the wrapper narrows them.

  • Tabs accepts controlled or uncontrolled value, onValueChange, orientation and size="sm" | "default" | "lg" | "xl" through the Base UI root contract.
  • TabsList accepts variant="default" | "underline" and can provide the size to its child tabs.
  • Each TabsTab requires a matching value and can be disabled or sized locally; render the corresponding content in TabsPanel.
  • TabsContent remains a compatibility alias for TabsPanel; new code should use the canonical TabsPanel name.

Motion

Component motion uses the shared Siteplane motion contract. See the global motion guide for provider setup, tokens and reduced-motion behavior.

  • The active indicator uses the native Siteplane position and size transition. Panels do not receive a heavy entrance animation.
  • The operating-system reduced-motion preference removes indicator interpolation. The forced reducedMotionPreset shortens the shared base duration from 180ms to 80ms while preserving selection and focus.

Accessibility

  • Preserve the tab, tablist and tabpanel relationship generated by Base UI.
  • Keep orientation consistent with both layout and arrow-key navigation.
  • Do not make a disabled tab the only path to required content.

Implementation Guidance

  • Use Stepper for workflow steps and navigation links for global routing.
  • Use canonical TabsPanel in new code and keep value pairs unique.
  • Do not replace native indicator, focus or orientation behavior.

On This Page