Skip to content
UI

Tabs

Switches between views of the same subject without leaving the page.

@zenoxai/ui/components/tabsBase UI Markdown
Lookalike domain acme-login.co, first seen 21 October, risk score 87.
<Tabs defaultValue="overview" className="w-full max-w-md">
  <TabsList>
    <TabsTrigger value="overview">Overview</TabsTrigger>
    <TabsTrigger value="evidence">Evidence</TabsTrigger>
    <TabsTrigger value="history">History</TabsTrigger>
  </TabsList>
  <TabsContent value="overview" className="text-text-secondary">
    Lookalike domain acme-login.co, first seen 21 October, risk score 87.
  </TabsContent>
  <TabsContent value="evidence" className="text-text-secondary">
    2 screenshots, 1 WHOIS record and the MX records of the domain.
  </TabsContent>
  <TabsContent value="history" className="text-text-secondary">
    Created by domain monitoring. Assigned to the SOC team.
  </TabsContent>
</Tabs>

Usage

import {
  Tabs,
  TabsContent,
  TabsList,
  TabsTrigger,
} from "@zenoxai/ui/components/tabs"
<Tabs defaultValue="overview">
  <TabsList>
    <TabsTrigger value="overview">Overview</TabsTrigger>
    <TabsTrigger value="evidence">Evidence</TabsTrigger>
  </TabsList>
  <TabsContent value="overview">...</TabsContent>
  <TabsContent value="evidence">...</TabsContent>
</Tabs>

Use tabs for views of equal weight that the user switches between: the sections of an alert, the status pivots of a list. Each TabsTrigger and its TabsContent share a value. Keep labels to one or two words and keep the set to what fits on one line.

The default variant looks like a segmented Toggle Group: the same bordered track, and the active tab takes the same selection colors, a primary-soft fill and text in a primary inset ring, while hover stays neutral. Choose between the two by what they switch: tabs swap panels, a toggle group changes what one view shows.

Do not use tabs for steps the user must complete in order, or to navigate between pages: use links. For a short set of options that filter a list in place, use the toggle group.

Examples

Line

variant="line" on TabsList is the tab row under the title of every Zenox module page. The list spans its container and draws its own bottom rule, and the active tab is marked by primary text over an underline in the primary color. Put counts in a soft Badge after the label. When the tabs do not fit, on a phone for example, the row scrolls sideways and keeps its rule; focusing a tab scrolls it into view.

24 alerts are waiting for triage.
<Tabs defaultValue="open" className="w-full">
  <TabsList variant="line">
    <TabsTrigger value="open">
      Open
      <Badge variant="soft" tone="neutral">
        24
      </Badge>
    </TabsTrigger>
    <TabsTrigger value="in-progress">
      In progress
      <Badge variant="soft" tone="neutral">
        6
      </Badge>
    </TabsTrigger>
    <TabsTrigger value="resolved">Resolved</TabsTrigger>
    <TabsTrigger value="dismissed">Dismissed</TabsTrigger>
  </TabsList>
  <TabsContent value="open" className="pt-2 text-text-secondary">
    24 alerts are waiting for triage.
  </TabsContent>
  <TabsContent value="in-progress" className="pt-2 text-text-secondary">
    6 alerts are assigned to an analyst.
  </TabsContent>
  <TabsContent value="resolved" className="pt-2 text-text-secondary">
    Alerts closed in the last 90 days.
  </TabsContent>
  <TabsContent value="dismissed" className="pt-2 text-text-secondary">
    Alerts marked as false positives.
  </TabsContent>
</Tabs>

Vertical

Set orientation="vertical" on Tabs for settings pages with more sections than fit in a row. The arrow keys follow the orientation: Up and Down move between tabs.

Send an email when a critical alert opens.
<Tabs
  defaultValue="notifications"
  orientation="vertical"
  className="w-full max-w-md"
>
  <TabsList>
    <TabsTrigger value="notifications">
      <BellIcon />
      Notifications
    </TabsTrigger>
    <TabsTrigger value="members">
      <UsersIcon />
      Members
    </TabsTrigger>
    <TabsTrigger value="api-keys">
      <KeyRoundIcon />
      API keys
    </TabsTrigger>
  </TabsList>
  <TabsContent value="notifications" className="text-text-secondary">
    Send an email when a critical alert opens.
  </TabsContent>
  <TabsContent value="members" className="text-text-secondary">
    12 members in the Acme Corp tenant.
  </TabsContent>
  <TabsContent value="api-keys" className="text-text-secondary">
    2 active keys. The oldest was created 140 days ago.
  </TabsContent>
</Tabs>

Accessibility

  • The list has role="tablist", each trigger role="tab" with aria-selected, and each panel role="tabpanel" labelled by its tab. Arrow keys move between tabs, Home and End jump to the first and last.
  • By default the arrow keys move focus without selecting; Enter or Space selects. Set activateOnFocus on TabsList to select on focus, only when panels render without delay.
  • Base UI flips Left and Right in a right-to-left layout. See Direction.

API reference

Generated from the TypeScript source. className, style and children are accepted everywhere and omitted below.

Tabs

Tabs switches between views of one subject that share a place on the page, such as the overview and the history of a record. Compose a TabsList with a TabsTrigger per view, and a TabsContent per view matched by `value`. For a control that filters the same list, use ToggleGroup.

PropTypeDefault
defaultValueany

The default value. Use when the component is not controlled. When the value is `null`, no Tab will be active.

0
onValueChange((value: any, eventDetails: TabsRootChangeEventDetails) => void)

Callback invoked when new value is being set.

-
orientation"horizontal" | "vertical"

The component orientation (layout flow direction).

horizontal
renderReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, TabsRootState>

Allows you to replace the component's HTML element with a different tag, or compose it with another component.

-
valueany

The value of the currently active `Tab`. Use when the component is controlled. When the value is `null`, no Tab will be active.

-

TabsList

TabsList is the row of TabsTrigger buttons.

PropTypeDefault
activateOnFocusboolean

Whether to automatically change the active tab on arrow key focus. Otherwise, tabs will be activated using <kbd>Enter</kbd> or <kbd>Space</kbd> key press.

false
loopFocusboolean

Whether to loop keyboard focus back to the first item when the end of the list is reached while using the arrow keys.

true
renderReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, TabsListState>

Allows you to replace the component's HTML element with a different tag, or compose it with another component.

-
variant"line" | "default" | null

`default` is a bordered track whose active tab takes the selection colors, the same control as a segmented ToggleGroup; `line` is a full-width bar on a bottom rule, with the active tab underlined, for page headers, sheets and status pivots.

default

TabsTrigger

PropTypeDefault
disabledboolean

Whether the Tab is disabled.

-
nativeButtonboolean

Whether the component renders a native `<button>` element when replacing it via the `render` prop. Set to `false` if the rendered element is not a button (for example, `<div>`).

true
renderReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, TabsTabState>

Allows you to replace the component's HTML element with a different tag, or compose it with another component.

-
value*any

The value of the Tab.

-

TabsContent

PropTypeDefault
keepMountedboolean

Whether to keep the HTML element in the DOM while the panel is hidden.

false
renderReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, TabsPanelState>

Allows you to replace the component's HTML element with a different tag, or compose it with another component.

-
value*any

The value of the TabPanel. It will be shown when the Tab with the corresponding value is active.

-

TabsIndicator

TabsIndicator is a bar that slides to the active tab. Place it inside a TabsList with `variant="line"` for an animated underline; Base UI sets the `--active-tab-{width,height,left,top}` variables it moves with.

PropTypeDefault
renderReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, TabsIndicatorState>

Allows you to replace the component's HTML element with a different tag, or compose it with another component.

-
renderBeforeHydrationboolean

Whether to render itself before React hydrates. This minimizes the time that the indicator isn't visible after server-side rendering.

false