Tabs Component

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.

Usage

Basic Tabs

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>

Controlled 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>

Vertical Orientation

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>

With Disabled Tab

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>

Default Index

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>

Status Colors

Tabs support different status colors for semantic meaning. The status can be set on the Tabs container or overridden per individual tab.

Container Status

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>

Per-Tab Status Override

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>

Container Context

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>

Tabs Props

NameTypeDefaultDescription
childrenJSXElementrequired

Tabs.Tab elements

indexnumberundefined

Controlled active tab index

defaultIndexnumber0

Initial active tab index (uncontrolled mode)

onIndexChange(index: number) => voidundefined

Callback when active tab changes

orientation"horizontal" | "vertical""horizontal"

Tab layout direction

statusStatusfrom ContainerContext or 'background'

Status color for all tabs (can be overridden per-tab)

stylesStyleXStylesundefined

StyleX overrides for the outer container

tabListStylesStyleXStylesundefined

StyleX overrides for the tab button list

tabStylesStyleXStylesundefined

StyleX overrides for all tab buttons (can be overridden per-tab)

panelStylesStyleXStylesundefined

StyleX overrides for the panel area

Tabs.Tab Props

NameTypeDefaultDescription
labelstringrequired

Tab button label text

childrenJSXElementrequired

Panel content

disabledbooleanfalse

Whether the tab is disabled

statusStatusinherited

Override status color for this tab

stylesStyleXStylesundefined

StyleX overrides for the tab button

panelStylesStyleXStylesundefined

StyleX overrides for this tab's panel

Keyboard Navigation

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.

Accessibility

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

Behavior

Controlled vs Uncontrolled

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.

Panel Rendering

Only the active panel is rendered at a time. Inactive panels are not in the DOM, which can improve performance for complex tab content.

Overflow

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.