A tabbed interface component for organizing content into switchable panels. Supports horizontal and vertical orientations with button-like tab styling. Selected tabs use filled button style, unselected tabs use outline style.
Overview content here
<Tabs>
<Tabs.Tab label="Overview">
<Text.body>Overview content here</Text.body>
</Tabs.Tab>
<Tabs.Tab label="Details">
<Text.body>Details content here</Text.body>
</Tabs.Tab>
<Tabs.Tab label="Settings">
<Text.body>Settings content here</Text.body>
</Tabs.Tab>
</Tabs>Current tab index: 0
Content for tab 1
const [activeTab, setActiveTab] = createSignal(0);
<Tabs index={activeTab()} onIndexChange={setActiveTab}>
<Tabs.Tab label="Tab 1">Content 1</Tabs.Tab>
<Tabs.Tab label="Tab 2">Content 2</Tabs.Tab>
<Tabs.Tab label="Tab 3">Content 3</Tabs.Tab>
</Tabs>Profile settings content
<Tabs orientation="vertical"> <Tabs.Tab label="Profile">Profile settings</Tabs.Tab> <Tabs.Tab label="Security">Security settings</Tabs.Tab> <Tabs.Tab label="Notifications">Notification preferences</Tabs.Tab> </Tabs>
This content is available
<Tabs>
<Tabs.Tab label="Available">
<Text.body>This content is available</Text.body>
</Tabs.Tab>
<Tabs.Tab label="Coming Soon" disabled>
<Text.body>This feature is not yet available</Text.body>
</Tabs.Tab>
<Tabs.Tab label="Also Available">
<Text.body>This content is also available</Text.body>
</Tabs.Tab>
</Tabs>Use defaultIndex to set which tab is initially selected in uncontrolled mode:
This tab is selected by default
<Tabs defaultIndex={1}>
<Tabs.Tab label="First">First tab content</Tabs.Tab>
<Tabs.Tab label="Second (default)">This tab is selected by default</Tabs.Tab>
<Tabs.Tab label="Third">Third tab content</Tabs.Tab>
</Tabs>Tabs support different status colors for semantic meaning. The status can be set on the Tabs container or overridden per individual tab.
Primary:
Content A
Success:
Content A
Warning:
Content A
Danger:
Content A
<Tabs status="primary">...</Tabs> <Tabs status="success">...</Tabs> <Tabs status="warning">...</Tabs> <Tabs status="danger">...</Tabs>
Individual tabs can override the container's status:
This tab uses the container's primary status
<Tabs status="primary"> <Tabs.Tab label="Normal">Normal tab</Tabs.Tab> <Tabs.Tab label="Warning" status="warning">Warning tab</Tabs.Tab> <Tabs.Tab label="Danger" status="danger">Danger tab</Tabs.Tab> </Tabs>
When placed inside a Container component, Tabs automatically inherits the container's status and adjusts styling for proper contrast. The border radius also adjusts based on container nesting depth.
This tabs component inherits the container's primary status
<Container status="primary">
<Tabs>
<Tabs.Tab label="Inside Container">
This tabs component inherits the container's status
</Tabs.Tab>
<Tabs.Tab label="Second Tab">
Tab styling adjusts for container context
</Tabs.Tab>
</Tabs>
</Container>| Name | Type | Default | Description |
|---|---|---|---|
children | JSXElement | required | Tabs.Tab elements |
index | number | undefined | Controlled active tab index |
defaultIndex | number | 0 | Initial active tab index (uncontrolled mode) |
onIndexChange | (index: number) => void | undefined | Callback when active tab changes |
orientation | "horizontal" | "vertical" | "horizontal" | Tab layout direction |
status | Status | from ContainerContext or 'background' | Status color for all tabs (can be overridden per-tab) |
styles | StyleXStyles | undefined | StyleX overrides for the outer container |
tabListStyles | StyleXStyles | undefined | StyleX overrides for the tab button list |
tabStyles | StyleXStyles | undefined | StyleX overrides for all tab buttons (can be overridden per-tab) |
panelStyles | StyleXStyles | undefined | StyleX overrides for the panel area |
| Name | Type | Default | Description |
|---|---|---|---|
label | string | required | Tab button label text |
children | JSXElement | required | Panel content |
disabled | boolean | false | Whether the tab is disabled |
status | Status | inherited | Override status color for this tab |
styles | StyleXStyles | undefined | StyleX overrides for the tab button |
panelStyles | StyleXStyles | undefined | StyleX overrides for this tab's panel |
The Tabs component follows the WAI-ARIA tabs pattern with automatic activation. Keyboard navigation varies based on orientation:
Horizontal orientation: Use Arrow Left/Right to navigate between tabs
Vertical orientation: Use Arrow Up/Down to navigate between tabs
Home: Move to and select first tab
End: Move to and select last tab
Navigation wraps around - pressing right on the last tab moves to the first tab. Disabled tabs are automatically skipped during keyboard navigation.
The Tabs component includes comprehensive accessibility features:
Tab list has role="tablist" with aria-orientation
Tab buttons have role="tab" with aria-selected and aria-controls
Panels have role="tabpanel" with aria-labelledby
Disabled tabs have aria-disabled set
Roving tabindex - only selected tab is focusable with Tab key
Focus-visible outline for keyboard users
Respects prefers-reduced-motion for animations
Uncontrolled: When index prop is not provided, the component manages its own state. Use defaultIndex to set the initial tab.
Controlled: When index prop is provided, the component is fully controlled by the parent. Use onIndexChange to handle tab changes.
Only the active panel is rendered at a time. Inactive panels are not in the DOM, which can improve performance for complex tab content.
No built-in overflow handling. If tabs exceed container width/height, they will overflow. The consuming application is responsible for managing tab count or container size.