Components

Tabs

Headless tab primitives for switching between related panels.

When to Use

Use Tabs to switch between a small set of related views without leaving the current page. Use normal links when each choice is a separate destination, and use Accordion when people should be able to see several sections open at once.

Features

  • Implements linked tab and tabpanel ARIA.
  • Supports controlled and uncontrolled selected value.
  • Supports horizontal and vertical orientation.
  • Supports RTL-aware horizontal arrow-key navigation.
  • Supports automatic or manual activation.
  • Supports disabled tabs, keep-mounted panels, focusable panels, and an optional indicator.

Import

import { Tabs } from "@flowstack-ui/atom";

Anatomy

<Tabs.Root>
  <Tabs.List>
    <Tabs.Trigger />
    <Tabs.Indicator />
  </Tabs.List>
  <Tabs.Content />
</Tabs.Root>

API Reference

Root

Owns selection, orientation, direction, activation mode, and the trigger registry used for roving focus.

ARIA: Root adds no role or ARIA attributes.

PropTypeDefault
valuestring-
defaultValuestring-
onValueChange(value: string) => void-
orientation"horizontal" | "vertical""horizontal"
dir"ltr" | "rtl"Direction.Provider
activationMode"automatic" | "manual""automatic"
loopbooleantrue
asChildbooleanfalse
renderRenderProp-
Data attributeValues
[data-slot]"tabs-root"
[data-orientation]"horizontal" | "vertical"

List

Provides the tablist container and owns Arrow, Home, and End navigation among enabled Trigger parts.

PropTypeDefault
ariaLabelstring-
asChildbooleanfalse
renderRenderProp-
ARIA attributeValues
role"tablist"
aria-labelValue from ariaLabel when provided
aria-orientationRoot orientation
Data attributeValues
[data-slot]"tabs-list"
[data-orientation]"horizontal" | "vertical"

Trigger

Renders one roving-focus tab and connects it to Content with generated IDs. Automatic mode selects on focus; manual mode waits for activation.

PropTypeDefault
valuestringrequired
disabledbooleanfalse
asChildbooleanfalse
renderRenderProp-
ARIA attributeValues
role"tab"
aria-selectedtrue when active
aria-controlsMatching Content ID
aria-disabledtrue when disabled
Data attributeValues
[data-slot]"tabs-trigger"
[data-state]"active" | "inactive"
[data-disabled]Present when disabled
[data-orientation]Root orientation
[data-value]Trigger value

Content

Renders the panel linked to its Trigger. Inactive panels unmount unless keepMounted is enabled; focusable opts the panel into the Tab order.

PropTypeDefault
valuestringrequired
keepMountedbooleanfalse
focusablebooleanfalse
asChildbooleanfalse
renderRenderProp-
ARIA attributeValues
role"tabpanel"
aria-labelledbyMatching Trigger ID
Data attributeValues
[data-slot]"tabs-content"
[data-state]"active" | "inactive"
[data-orientation]Root orientation

Indicator

Measures the active Trigger and exposes its position through CSS variables. It renders only after an active Trigger can be measured.

ARIA: Indicator is decorative and adds no role or ARIA attributes.

Data attributeValues
[data-slot]"tabs-indicator"
[data-orientation]"horizontal" | "vertical"

Indicator renders only when it can measure the active trigger. It exposes the active trigger position through --tabs-indicator-left, --tabs-indicator-top, --tabs-indicator-width, and --tabs-indicator-height.

Advanced compound parts can read useTabsContext or use the public TabsContextProvider.

Examples

Manual Activation

import { Tabs } from "@flowstack-ui/atom";

export default function ManualTabs() {
  return (
<Tabs.Root defaultValue="preview" activationMode="manual">
  <Tabs.List>
    <Tabs.Trigger value="preview">Preview</Tabs.Trigger>
    <Tabs.Trigger value="code">Code</Tabs.Trigger>
  </Tabs.List>
  <Tabs.Content value="preview">Preview panel</Tabs.Content>
  <Tabs.Content value="code">Code panel</Tabs.Content>
</Tabs.Root>
  );
}

Keep Panels Mounted

import { Tabs } from "@flowstack-ui/atom";

export default function MountedTabs() {
  return (
    <Tabs.Root defaultValue="profile">
      <Tabs.List><Tabs.Trigger value="profile">Profile</Tabs.Trigger><Tabs.Trigger value="settings">Settings</Tabs.Trigger></Tabs.List>
      <Tabs.Content value="profile" keepMounted>Profile</Tabs.Content>
      <Tabs.Content value="settings" keepMounted>Settings</Tabs.Content>
    </Tabs.Root>
  );
}

Accessibility

Tabs follows the WAI-ARIA tabs pattern. Triggers and panels have stable ID relationships. Horizontal navigation mirrors in RTL; vertical navigation does not change with text direction.

KeyDescription
ArrowRight / ArrowLeftMoves between horizontal tabs; mirrored when dir="rtl"
ArrowDown / ArrowUpMoves between vertical tabs
Home / EndMoves to first or last tab
Enter / SpaceActivates a tab in manual mode
TabMoves focus into the active panel or next focusable element

Changelog

See CHANGELOG.md.