Skip to main content
Version: Next

Tabs

A fully accessible tabbed interface. Uses a composed pattern — Tabs.Tab defines each tab trigger and Tabs.Panel defines the corresponding content panel.

Import​

import { Tabs } from '@editora/ui-react';
// or subpath
import { Tabs } from '@editora/ui-react/Tabs';

Basic Usage​

Live Editor
function TabsDemo() {
  return (
    <ThemeProvider>
      <Tabs selected={0} variant="soft" onChange={(index) => console.log(index)}>
        <Tabs.Tab value="overview">Overview</Tabs.Tab>
        <Tabs.Panel>Overview content here.</Tabs.Panel>

        <Tabs.Tab value="activity">Activity</Tabs.Tab>
        <Tabs.Panel>Activity content here.</Tabs.Panel>
      </Tabs>
    </ThemeProvider>
  );
}
Result
Loading...

With Icons​

<Tabs selected={0} variant="cards">
<Tabs.Tab value="dashboard" icon="📊">Dashboard</Tabs.Tab>
<Tabs.Panel>KPIs and trend deltas.</Tabs.Panel>

<Tabs.Tab value="alerts" icon="⚡">Alerts</Tabs.Tab>
<Tabs.Panel>Delivery retries and queue throughput.</Tabs.Panel>
</Tabs>

Disabled Tab​

<Tabs selected={0}>
<Tabs.Tab value="profile">Profile</Tabs.Tab>
<Tabs.Panel>Profile settings.</Tabs.Panel>

<Tabs.Tab value="billing" disabled>Billing</Tabs.Tab>
<Tabs.Panel>Billing details.</Tabs.Panel>
</Tabs>

Controlled​

const [selected, setSelected] = useState(0);

<Tabs selected={selected} onChange={setSelected}>
<Tabs.Tab value="a">Tab A</Tabs.Tab>
<Tabs.Panel>Panel A</Tabs.Panel>

<Tabs.Tab value="b">Tab B</Tabs.Tab>
<Tabs.Panel>Panel B</Tabs.Panel>
</Tabs>

Vertical Orientation​

<Tabs orientation="vertical" activation="manual" variant="indicator-line" selected={0}>
<Tabs.Tab value="profile">Profile</Tabs.Tab>
<Tabs.Panel>Profile content.</Tabs.Panel>

<Tabs.Tab value="security">Security</Tabs.Tab>
<Tabs.Panel>Security content.</Tabs.Panel>
</Tabs>

Variants​

// Segmented — compact switch-like
<Tabs variant="segmented" selected={0}>...</Tabs>

// Line — minimal underline
<Tabs variant="line" selected={0}>...</Tabs>

// Cards — elevated surface separation
<Tabs variant="cards" selected={0}>...</Tabs>

// Animated pill indicator
<Tabs variant="indicator" selected={0}>...</Tabs>

// Animated underline indicator
<Tabs variant="indicator-line" selected={0}>...</Tabs>

// Contrast — dark command-center
<Tabs variant="contrast" selected={0}>...</Tabs>

Props​

Tabs (root)​

PropTypeDefaultDescription
selectednumber | string0Selected tab index or value
valuestring—Selected tab by value (alternative to selected)
orientation'horizontal' | 'vertical''horizontal'Tab list direction
activation'auto' | 'manual''auto'auto selects on focus; manual requires Enter/Space
variant'default' | 'soft' | 'outline' | 'solid' | 'ghost' | 'glass' | 'indicator' | 'indicator-line' | 'contrast' | 'minimal' | 'underline' | 'line' | 'segmented' | 'cards''default'Visual style
size'sm' | 'md' | 'lg''md'Tab size
density'compact' | 'default' | 'comfortable''default'Spacing density
tone'brand' | 'success' | 'warning' | 'danger''brand'Accent color
shape'rounded' | 'square' | 'pill''rounded'Tab border radius
elevation'low' | 'none' | 'high''low'Box shadow depth
stretchedbooleanfalseTabs fill the full nav width
loopbooleantrueKeyboard navigation wraps around
barebooleanfalseRemoves nav and panel borders/backgrounds
headlessbooleanfalseHides nav and panel, renders slots only
onChange(index: number) => void—Fires with selected index on change
onTabChange(detail: TabsDetail) => void—Fires with full detail object on change

Tabs.Tab​

PropTypeDefaultDescription
valuestring—Unique identifier for this tab
iconstring—Emoji or text icon shown before label
disabledbooleanfalseSkips tab in keyboard navigation
childrenReact.ReactNode—Tab label content
...restReact.HTMLAttributes<HTMLElement>—Passed to inner <div>

Tabs.Panel​

PropTypeDescription
childrenReact.ReactNodePanel content
...restReact.HTMLAttributes<HTMLElement>Passed to inner <div>

Event Detail​

type TabsDetail = {
selected: number;
index: number;
value: string;
label: string;
tabId: string;
panelId: string;
};

Notes​

  • Tabs.Tab and Tabs.Panel are paired by order — the first Tab corresponds to the first Panel, and so on.
  • Keyboard: ArrowLeft/ArrowRight (horizontal) or ArrowUp/ArrowDown (vertical) navigate tabs. Home/End jump to first/last. Enter/Space select in manual activation mode.
  • Disabled tabs are skipped during keyboard traversal and cannot be selected.
  • variant="indicator" and variant="indicator-line" render an animated moving indicator that tracks the selected tab.