Tabs

Segmented navigation component for switching between related views.

The Tabs component lets users switch between related views without leaving the page. It is built on Radix UI Tabs and styled with PyColors tokens for consistent theming.

Use Tabs for:

  • Settings sections (Profile / Billing / Security)
  • Dashboards (Overview / Activity / Logs)
  • Compact UIs (filters, panels, segmented content)

Import

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

Usage

Account settings content

<Tabs defaultValue="account">
  <TabsList aria-label="Settings tabs">
    <TabsTrigger value="account">Account</TabsTrigger>
    <TabsTrigger value="password">Password</TabsTrigger>
  </TabsList>

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

export function SettingsTabs() {
  return (
    <Tabs defaultValue="account" className="w-full max-w-xl">
      <TabsList aria-label="Settings tabs">
        <TabsTrigger value="account">Account</TabsTrigger>
        <TabsTrigger value="password">Password</TabsTrigger>
      </TabsList>

      <TabsContent value="account">
        <div className="rounded-md border bg-card p-4 text-sm">
          Account settings content
        </div>
      </TabsContent>

      <TabsContent value="password">
        <div className="rounded-md border bg-card p-4 text-sm">
          Password settings content
        </div>
      </TabsContent>
    </Tabs>
  );
}

Sizes

TabsList and TabsTrigger accept a size prop to adapt density.

Small tabs content

Medium tabs content

Large tabs content

<TabsList size="sm">...</TabsList>
<TabsTrigger size="sm" value="...">...</TabsTrigger>
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";

export function SizedTabsList() {
  return (
    <Tabs defaultValue="one">
      <TabsList size="sm" aria-label="Small tabs">
        <TabsTrigger size="sm" value="one">One</TabsTrigger>
        <TabsTrigger size="sm" value="two">Two</TabsTrigger>
      </TabsList>
    </Tabs>
  );
}

Available sizes

SizeDescription
smDense UIs (filters, toolbars)
mdDefault density
lgComfortable spacing (marketing / onboarding)

API

Components

ComponentDescription
TabsRoot container (Radix TabsPrimitive.Root)
TabsListTrigger list (supports size)
TabsTriggerIndividual trigger (supports size)
TabsContentContent panel

Props

  • Tabs extends TabsPrimitive.TabsProps
  • TabsList extends TabsPrimitive.TabsListProps + { size?: "sm" | "md" | "lg" }
  • TabsTrigger extends TabsPrimitive.TabsTriggerProps + { size?: "sm" | "md" | "lg" }
  • TabsContent extends TabsPrimitive.TabsContentProps

TypeScript types

export type TabsSize = "sm" | "md" | "lg";

Accessibility

  • Always provide an aria-label on TabsList (or associate with a visible heading).
  • Ensure each TabsTrigger has clear text (avoid icon-only triggers).
  • Keyboard support is built-in via Radix (Arrow keys to navigate triggers).
  • Keep tab labels short and descriptive.

Design guidelines

  • Use Tabs when the views are peers (same hierarchy).
  • Don’t hide critical actions behind tabs; keep actions visible in the page header.
  • Prefer 2–5 tabs; more than that usually becomes a navigation problem.
  • Keep content height stable when possible to reduce layout shift.