Tabs
Switch between related views.
Preview
Overview panel content.
Code
import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs";
export function Example() {
return (
<Tabs defaultValue="overview">
<TabsList>
<TabsTrigger value="overview">Overview</TabsTrigger>
<TabsTrigger value="activity">Activity</TabsTrigger>
<TabsTrigger value="settings">Settings</TabsTrigger>
</TabsList>
<TabsContent value="overview">Overview content.</TabsContent>
<TabsContent value="activity">Activity content.</TabsContent>
<TabsContent value="settings">Settings content.</TabsContent>
</Tabs>
);
}Props
| Prop | Type | Default | Description |
|---|---|---|---|
| value | string | — | Controlled active tab value. |
| defaultValue | string | — | Uncontrolled initial active tab. |
| onValueChange | (value: string) => void | — | Called when the active tab changes. |
| orientation | "horizontal" | "vertical" | "horizontal" | Tab list orientation. |
| className | string | — | Additional Tailwind classes, merged with the component's defaults via cn(). |
Sub-components
TabsList— Container for the trigger buttons.TabsTrigger— Individual tab button.| Prop | Type | Default | Description |
|---|---|---|---|
| value | string | — | Matches a panel's value. |
TabsContent— Panel content shown when its value is active.| Prop | Type | Default | Description |
|---|---|---|---|
| value | string | — | Matches a trigger's value. |
Built on Base UI Tabs. Selected trigger uses **accent-colored text** + raised surface (`data-active`). Keyboard: arrows navigate, Tab moves to content.
All components also accept standard HTML attributes for their root element (e.g. `id`, `aria-*`, `data-*`, event handlers) and forward `ref` where applicable.
Source
The full implementation of components/ui/tabs.tsx is below — copy it into your project and own it. Some components import the cn helper from lib/utils or other primitives; copy those too.
"use client";
import { cn } from "@/lib/utils";
import { Tabs as BaseTabs } from "@base-ui-components/react/tabs";
import type { ComponentPropsWithoutRef } from "react";
export const Tabs = BaseTabs.Root;
export function TabsList({ className, ...props }: ComponentPropsWithoutRef<typeof BaseTabs.List>) {
return (
<BaseTabs.List
className={cn(
"relative inline-flex h-9 items-center justify-center rounded-md bg-bg-muted p-1 text-fg-muted",
className,
)}
{...props}
/>
);
}
export function TabsTrigger({
className,
...props
}: ComponentPropsWithoutRef<typeof BaseTabs.Tab>) {
return (
<BaseTabs.Tab
className={cn(
"inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1 text-sm font-medium transition-all",
"text-fg-muted hover:text-fg",
"focus-visible:outline-1 focus-visible:outline-offset-0 focus-visible:outline-accent",
"data-[active]:bg-surface data-[active]:text-accent data-[active]:shadow-sm",
"data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
className,
)}
{...props}
/>
);
}
export function TabsContent({
className,
...props
}: ComponentPropsWithoutRef<typeof BaseTabs.Panel>) {
return (
<BaseTabs.Panel
className={cn(
"mt-2",
"focus-visible:outline-1 focus-visible:outline-offset-0 focus-visible:outline-accent",
className,
)}
{...props}
/>
);
}JavaFX
Ships in the PRIZM JavaFX library for thick-client C3 apps as PrizmTabs (extends TabPane). Run the gallery to see it natively.
import design.prizm.fx.controls.PrizmTabs;
PrizmTabs()| Prop | Type | Default | Description |
|---|---|---|---|
| tabs | ObservableList<Tab> | — | Add Tabs via getTabs(); closing policy defaults to UNAVAILABLE. |
Thin TabPane subclass; muted labels, accent + muted-fill on the selected tab, via the .prizm-tabs rules. Mirrors components/ui/tabs.tsx.