Overview
Use for
- Segmenting dashboard content (overview, analytics, billing).
- Switching between media views (grid vs. list).
- Form wizards where each tab is a step with persistent context.
Avoid for
- Navigation across distinct pages—use sidebar or top nav.
- More than six options; tabs should remain scannable without scrolling.
- Asynchronous content loads without skeletons—use inline loaders.
Examples
Dashboard switcher
Account overview
Latest stats across Remix projects.
42 new remixes today
import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs"
export function DashboardTabs() {
return (
<Tabs defaultValue="overview" className="w-full">
<TabsList>
<TabsTrigger value="overview">Overview</TabsTrigger>
<TabsTrigger value="photos">Photos</TabsTrigger>
<TabsTrigger value="activity">Activity</TabsTrigger>
</TabsList>
<TabsContent value="overview">Overview content</TabsContent>
<TabsContent value="photos">Photo grid</TabsContent>
<TabsContent value="activity">Activity logs</TabsContent>
</Tabs>
)
}Controlled state
Overview content
import { useState } from "react"
import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs"
export function ControlledTabs() {
const [value, setValue] = useState("overview")
return (
<Tabs value={value} onValueChange={setValue}>
<TabsList>
<TabsTrigger value="overview">Overview</TabsTrigger>
<TabsTrigger value="billing">Billing</TabsTrigger>
</TabsList>
<TabsContent value="overview">Overview content</TabsContent>
<TabsContent value="billing">Billing content</TabsContent>
</Tabs>
)
}Props
| Prop | Type | Default | Description |
|---|---|---|---|
defaultValue | string | — | Initial active tab value for uncontrolled usage. |
value | string | — | Controlled active tab value. |
onValueChange | (value: string) => void | — | Callback fired when a different tab is selected. |
Accessibility
Keyboard
- Use arrow keys to move between tabs; Tab moves focus into the active panel.
- Radix sets `role="tablist"`, `tab`, and `tabpanel` semantics automatically.
- Ensure each `TabsTrigger` has a unique value string.
Design guidance
- Keep labels short (1–2 words) to avoid overflow.
- Provide persistent context outside the tab list so the user knows what is switching.
- For mobile, consider wrapping triggers to a scrollable container with `overflow-x-auto`.