Tabs
Controlled tab wrapper. Uses `tablist` / `tabpanel` semantics, so reach for it when selecting an option shows or hides associated content panels. To pick a value without swapping panels — a styled radio group for filters, settings, or view modes — use SegmentedControl instead.
Examples
Section titled “Examples”Default
Section titled “Default”Overview content
Activity content
Settings content
Analytics content
Reports content
function TabsStory(args: React.ComponentProps<typeof Tabs>) { const [value, setValue] = useState(args.value); return ( <> <Tabs {...args} onChange={setValue} value={value}> <Tab controls="overview-panel" id="overview-tab" label="Overview" value="overview" /> <Tab controls="activity-panel" endContent={<Badge color="info" label="3" />} id="activity-tab" label="Activity" value="activity" /> <Tab controls="settings-panel" icon={Settings} id="settings-tab" label="Settings" value="settings" /> <Tab isDisabled label="Disabled" value="disabled" /> <TabMenu id="more-tabs-tab" label="More" options={[ { icon: BarChart3, label: 'Analytics', value: 'analytics', }, {label: 'Reports', value: 'reports'}, ]} /> </Tabs> <div aria-labelledby="overview-tab" hidden={value !== 'overview'} id="overview-panel" role="tabpanel"> Overview content </div> <div aria-labelledby="activity-tab" hidden={value !== 'activity'} id="activity-panel" role="tabpanel"> Activity content </div> <div aria-labelledby="settings-tab" hidden={value !== 'settings'} id="settings-panel" role="tabpanel"> Settings content </div> <div aria-labelledby="more-tabs-tab" hidden={value !== 'analytics'} id="analytics-panel" role="tabpanel"> Analytics content </div> <div aria-labelledby="more-tabs-tab" hidden={value !== 'reports'} id="reports-panel" role="tabpanel"> Reports content </div> </> );}
<TabsStory {...args} />Active Highlight
Section titled “Active Highlight”function PackageManagersStory(args: React.ComponentProps<typeof Tabs>) { const [value, setValue] = useState('yarn'); return ( <Tabs {...args} hasDivider onChange={setValue} value={value}> <Tab label="npm" value="npm" /> <Tab label="pnpm" value="pnpm" /> <Tab label="yarn" value="yarn" /> </Tabs> );}
<PackageManagersStory {...args} />Overview content
Activity content
Settings content
Analytics content
Reports content
function TabsStory(args: React.ComponentProps<typeof Tabs>) { const [value, setValue] = useState(args.value); return ( <> <Tabs {...args} onChange={setValue} value={value}> <Tab controls="overview-panel" id="overview-tab" label="Overview" value="overview" /> <Tab controls="activity-panel" endContent={<Badge color="info" label="3" />} id="activity-tab" label="Activity" value="activity" /> <Tab controls="settings-panel" icon={Settings} id="settings-tab" label="Settings" value="settings" /> <Tab isDisabled label="Disabled" value="disabled" /> <TabMenu id="more-tabs-tab" label="More" options={[ { icon: BarChart3, label: 'Analytics', value: 'analytics', }, {label: 'Reports', value: 'reports'}, ]} /> </Tabs> <div aria-labelledby="overview-tab" hidden={value !== 'overview'} id="overview-panel" role="tabpanel"> Overview content </div> <div aria-labelledby="activity-tab" hidden={value !== 'activity'} id="activity-panel" role="tabpanel"> Activity content </div> <div aria-labelledby="settings-tab" hidden={value !== 'settings'} id="settings-panel" role="tabpanel"> Settings content </div> <div aria-labelledby="more-tabs-tab" hidden={value !== 'analytics'} id="analytics-panel" role="tabpanel"> Analytics content </div> <div aria-labelledby="more-tabs-tab" hidden={value !== 'reports'} id="reports-panel" role="tabpanel"> Reports content </div> </> );}
<TabsStory {...args} /><div style={{display: 'grid', gap: 16}}> <Tabs {...args} onChange={() => {}} size="sm" value="overview"> <Tab label="Overview" value="overview" /> <Tab label="Activity" value="activity" /> </Tabs> <Tabs {...args} onChange={() => {}} size="lg" value="overview"> <Tab label="Overview" value="overview" /> <Tab label="Activity" value="activity" /> </Tabs></div>Divider
Section titled “Divider”<div style={{display: 'grid', gap: 16}}> <Tabs {...args} hasDivider={false} onChange={() => {}} value="overview"> <Tab label="Overview" value="overview" /> <Tab label="Activity" value="activity" /> </Tabs> <Tabs {...args} hasDivider onChange={() => {}} value="overview"> <Tab label="Overview" value="overview" /> <Tab label="Activity" value="activity" /> </Tabs></div>Link Tabs
Section titled “Link Tabs”<Tabs {...args} onChange={() => {}} value="overview"> <Tab href="/overview" label="Overview" value="overview" /> <Tab href="/activity" label="Activity" value="activity" /> <Tab href="/settings" label="Settings" value="settings" /></Tabs>Custom Link
Section titled “Custom Link”<Tabs {...args} onChange={() => {}} value="overview"> <Tab as={RouterLink} href="/overview" label="Overview" value="overview" /> <Tab as={RouterLink} href="/activity" label="Activity" value="activity" /> <Tab as={RouterLink} href="/settings" label="Settings" value="settings" /></Tabs>Selected Icon
Section titled “Selected Icon”function SelectedIconStory(args: React.ComponentProps<typeof Tabs>) { const [value, setValue] = useState('notifications'); return ( <Tabs {...args} onChange={setValue} value={value}> <Tab icon={Home} label="Home" value="home" /> <Tab icon={Bell} label="Notifications" selectedIcon={BellRing} value="notifications" /> <Tab icon={Settings} label="Settings" value="settings" /> </Tabs> );}
<SelectedIconStory {...args} />Disabled
Section titled “Disabled”<Tabs {...args} onChange={() => {}} value="overview"> <Tab label="Overview" value="overview" /> <Tab isDisabled label="Activity" value="activity" /> <TabMenu isDisabled label="More" options={[{label: 'Reports', value: 'reports'}]} /></Tabs>Tab Menu Only
Section titled “Tab Menu Only”function TabMenuOnlyStory(args: React.ComponentProps<typeof Tabs>) { const [value, setValue] = useState('analytics'); return ( <Tabs {...args} onChange={setValue} value={value}> <TabMenu label="Views" options={[ {icon: BarChart3, label: 'Analytics', value: 'analytics'}, {icon: FileText, label: 'Reports', value: 'reports'}, {icon: Users, label: 'Audience', value: 'audience'}, ]} /> </Tabs> );}
<TabMenuOnlyStory {...args} />Many Tabs
Section titled “Many Tabs”function ManyTabsStory(args: React.ComponentProps<typeof Tabs>) { const [value, setValue] = useState('overview'); return ( <Tabs {...args} onChange={setValue} value={value}> <Tab label="Overview" value="overview" /> <Tab label="Activity" value="activity" /> <Tab label="Members" value="members" /> <Tab label="Files" value="files" /> <Tab label="Billing" value="billing" /> <Tab label="Security" value="security" /> <TabMenu label="More" options={[ {label: 'Analytics', value: 'analytics'}, {label: 'Reports', value: 'reports'}, {label: 'Integrations', value: 'integrations'}, ]} /> </Tabs> );}
<ManyTabsStory {...args} />Controlled
Section titled “Controlled”function ControlledStory(args: React.ComponentProps<typeof Tabs>) { const [value, setValue] = useState(args.value); return ( <Tabs {...args} onChange={setValue} value={value}> <Tab label="Overview" value="overview" /> <Tab label="Activity" value="activity" /> <Tab label="Settings" value="settings" /> </Tabs> );}
<ControlledStory {...args} />With Panels
Section titled “With Panels”Overview content
Activity content
function WithPanelsStory(args: React.ComponentProps<typeof Tabs>) { const [value, setValue] = useState('overview'); return ( <> <Tabs {...args} onChange={setValue} value={value}> <Tab controls="manual-overview-panel" id="manual-overview-tab" label="Overview" value="overview" /> <Tab controls="manual-activity-panel" id="manual-activity-tab" label="Activity" value="activity" /> </Tabs> <div aria-labelledby="manual-overview-tab" hidden={value !== 'overview'} id="manual-overview-panel" role="tabpanel"> Overview content </div> <div aria-labelledby="manual-activity-tab" hidden={value !== 'activity'} id="manual-activity-panel" role="tabpanel"> Activity content </div> </> );}
<WithPanelsStory {...args} /><div dir="rtl"> <Tabs {...args} onChange={() => {}} value="overview"> <Tab label="Overview" value="overview" /> <Tab label="Activity" value="activity" /> <Tab label="Settings" value="settings" /> </Tabs></div>Controlled tab wrapper. Uses `tablist` / `tabpanel` semantics, so reach for it when selecting an option shows or hides associated content panels. To pick a value without swapping panels — a styled radio group for filters, settings, or view modes — use SegmentedControl instead.
| Prop | Type | Default | Description |
|---|---|---|---|
children* | ReactNode | — | Tab and TabMenu children. |
className | string | — | Additional CSS class names applied to the tablist element. |
data-testid | string | — | Test ID applied to the tablist element. |
hasDivider | boolean | false | Whether to show a bottom divider. |
label | string | 'Tabs' | Accessible label for the tabs. |
layout | "fill" | "hug" | 'hug' | Tab layout mode. |
onChange* | (value: string) => void | — | Called when a tab is selected. |
ref | Ref<HTMLElement> | — | Ref forwarded to the tablist element. |
size | "sm" | "md" | "lg" | 'md' | Tab size. |
style | CSSProperties | — | Inline styles applied to the tablist element. |
value* | string | — | Current selected tab value. |
A single tab inside `Tabs`.
| Prop | Type | Default | Description |
|---|---|---|---|
as | LinkComponent | — | Custom link component used when href is set. |
className | string | — | Additional CSS class names applied to the tab. |
controls | string | — | ID of the tabpanel controlled by this tab. Use this for in-page tabs, and render the corresponding panel with id={controls}, role="tabpanel", and aria-labelledby pointing to this tab's id. |
data-testid | string | — | Test ID applied to the tab. |
endContent | ReactNode | — | Content rendered after the label. |
href | string | — | Optional link URL. When set, the tab renders as a link. |
icon | IconComponent | — | Icon shown before the label. |
id | string | — | ID applied to the tab element. Provide this with controls when rendering your own tabpanel so the panel can reference the tab with aria-labelledby. |
isDisabled | boolean | false | Whether the tab is disabled. |
label* | string | — | Visible tab label. |
ref | Ref<HTMLElement> | — | Ref forwarded to the tab root. |
selectedIcon | IconComponent | — | Icon shown when selected. Falls back to icon. |
style | CSSProperties | — | Inline styles applied to the tab. |
value* | string | — | Unique tab value. |
TabMenu
Section titled “TabMenu”Overflow menu for additional tabs.
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | — | Additional CSS class names applied to the trigger. |
data-testid | string | — | Test ID applied to the trigger. |
id | string | — | ID applied to the menu trigger tab. |
isDisabled | boolean | false | Whether the menu trigger is disabled. |
label* | string | — | Trigger and menu heading label. |
options* | ReadonlyArray<TabMenuOption> | — | Menu options. |
ref | Ref<HTMLButtonElement> | — | Ref forwarded to the trigger button. |
style | CSSProperties | — | Inline styles applied to the trigger. |