Tabs
Segmented navigation component for switching between related views.
Switch between related viewsLink to section
The Tabs component lets users switch between related views without leaving the page.
Use it for:
- settings sections
- dashboard views
- billing sections
- product panels
- compact filters
- segmented content
- related admin views
Tabs are built on Radix Tabs and styled with PyColors tokens for consistent theming, focus states, and interaction behavior.
Core idea
Tabs are for peer views at the same hierarchy level. They should not replace primary navigation.
ImportLink to section
import { Tabs } from "@pycolors/ui";Basic usageLink to section
Use Tabs when multiple related views belong inside the same page context.
Account settings content
import {
Tabs,
TabsList,
TabsTrigger,
TabsContent,
} from "@pycolors/ui";
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>
);
}When to use TabsLink to section
Use Tabs when users switch between related peer sections in the same workflow.
Settings sections
Use for Profile, Billing, Security, Notifications, and Danger Zone sections.
Dashboard views
Use for Overview, Activity, Logs, Usage, or Members inside a dashboard page.
Compact filters
Use for small segmented filters when the choices are few and stable.
SizesLink to section
TabsList and TabsTrigger accept a size prop to adapt density.
Small tabs content
Medium tabs content
Large tabs content
import {
Tabs,
TabsList,
TabsTrigger,
TabsContent,
} from "@pycolors/ui";
export function TabsSizes() {
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>
<TabsContent value="one">
Small tabs content
</TabsContent>
<TabsContent value="two">
Small tabs content
</TabsContent>
</Tabs>
);
}Available sizesLink to section
| Size | Purpose |
|---|---|
sm | Dense UIs, filters, toolbars |
md | Default density |
lg | Comfortable spacing, onboarding, marketing-like surfaces |
Density rule
Use sm for compact product controls, md for most product UI, and lg only when the tabs need stronger visual presence.
Product examplesLink to section
Settings tabs
Profile, Organization, Security, Billing, Notifications.
Billing tabs
Plan, Invoices, Payment method, Usage.
Dashboard tabs
Overview, Activity, Logs, Members.
Usage patternsLink to section
Use tabs for peer viewsLink to section
Each tab should represent a related view at the same hierarchy level.
Keep labels shortLink to section
Prefer labels like Overview, Activity, Billing, Security, Logs, Usage.
Limit the number of tabsLink to section
Two to five tabs usually works best. More than that often becomes navigation.
Keep important actions visibleLink to section
Do not hide critical actions inside a tab if users need them globally.
Preserve content structureLink to section
Each tab panel should have a clear heading or section structure when the content is complex.
Tabs vs navigation vs filtersLink to section
| Situation | Use |
|---|---|
| Switch between related peer views | Tabs |
| Move between pages or major product areas | Navigation |
| Toggle a small state filter | Tabs or segmented control |
| Select one value inside a form | Radio group |
| Hide or reveal optional content | Accordion |
| Switch between unrelated workflows | Page navigation |
Decision rule
If each option is a related view in the same page, use Tabs. If each option is a destination, use navigation.
APILink to section
ComponentsLink to section
| Component | Description |
|---|---|
Tabs | Root container |
TabsList | Trigger list, supports size |
TabsTrigger | Individual tab trigger, supports size |
TabsContent | Content panel |
Props
| Component | Props |
|---|---|
Tabs | Extends Radix TabsPrimitive.TabsProps |
TabsList | Extends Radix TabsPrimitive.TabsListProps + { size?: TabsSize } |
TabsTrigger | Extends Radix TabsPrimitive.TabsTriggerProps + { size?: TabsSize } |
TabsContent | Extends Radix TabsPrimitive.TabsContentProps |
TypeScript typesLink to section
export type TabsSize = "sm" | "md" | "lg";AccessibilityLink to section
Tabs are built on Radix Tabs primitives.
Guidelines:
- provide an
aria-labelonTabsListor associate it with a visible heading - keep each
TabsTriggerclear and text-based when possible - avoid icon-only tab triggers unless they have accessible labels
- keep keyboard navigation predictable
- ensure tab content is meaningful when reached directly
- avoid hiding critical product actions behind inactive tabs
Radix provides keyboard support:
- Arrow keys move between triggers
- Enter or Space activates a trigger depending on activation mode
- focus management follows tablist semantics
Accessibility rule
A tab label should clearly describe the content it reveals.
Prefer / avoidLink to section
Prefer
- 2–5 related peer views
- short labels
- clear
aria-labelon the list - stable content layout where possible
- page-level actions outside the tabs
Avoid
- too many tabs
- unrelated workflows in one tablist
- icon-only tabs without labels
- hiding critical actions inside tabs
- using tabs as global navigation
Product copy guidelinesLink to section
Tab labels should be short and familiar.
- Overview
- Activity
- Billing
- Security
- Logs
- Everything about your account
- Manage your billing details here
- Things that happened before
- Other configuration stuff