Tabs
Accessible tabs with horizontal/vertical orientation, automatic or manual activation, and full keyboard navigation. Currently only available in React.
Features
Horizontal or vertical orientation — controls arrow-key navigation direction.
Automatic activation (focus selects) or manual (Enter/Space to activate).
Full keyboard navigation: arrows, Home, End.
Skips disabled triggers during arrow-key navigation.
Optional
forceMount on Content to keep panels mounted (preserves state).Controlled or uncontrolled value.
Example
A high-level summary of the product features and what makes it special.
Anatomy
import { Tabs } from '@wire-ui/react'
<Tabs.Root defaultValue="overview">
<Tabs.List>
<Tabs.Trigger value="overview">Overview</Tabs.Trigger>
<Tabs.Trigger value="details">Details</Tabs.Trigger>
<Tabs.Trigger value="reviews">Reviews</Tabs.Trigger>
</Tabs.List>
<Tabs.Content value="overview">Overview content.</Tabs.Content>
<Tabs.Content value="details">Details content.</Tabs.Content>
<Tabs.Content value="reviews">Reviews content.</Tabs.Content>
</Tabs.Root>Styling
Trigger and Content expose data-state ("active" / "inactive") and data-orientation. Trigger also exposes the full interactive state set plus data-disabled.
<Tabs.Trigger className="
border-b-2 border-transparent
data-[state=active]:border-black
data-[state=active]:font-semibold
data-[disabled]:opacity-40
data-[focus-visible]:ring-2
">
Tab
</Tabs.Trigger>For vertical tabs, switch the indicator to the side:
<Tabs.Root orientation="vertical">
<Tabs.List className="flex flex-col border-r border-black">
<Tabs.Trigger
value="x"
className="border-r-2 border-transparent data-[state=active]:border-black"
/>
</Tabs.List>
</Tabs.Root>Using data attributes
[data-state="active"] { border-color: #000; font-weight: 600; }
[data-state="inactive"] { /* default */ }
[data-orientation="vertical"] { flex-direction: column; }
[data-disabled] { opacity: 0.4; cursor: not-allowed; }Root props
| Prop | Type | Default | Description |
|---|---|---|---|
value | string | — | Controlled active tab value |
defaultValue | string | — | Initial active tab (uncontrolled) |
onChange | (value: string) => void | — | Called when the active tab changes |
orientation | 'horizontal' | 'vertical' | 'horizontal' | Layout direction; controls arrow-key axis |
activationMode | 'automatic' | 'manual' | 'automatic' | automatic: focus activates; manual: Enter/Space activates |
Trigger props
| Prop | Type | Default | Description |
|---|---|---|---|
value | string | required | Unique value identifying this tab |
disabled | boolean | false | Disable this tab |
Content props
| Prop | Type | Default | Description |
|---|---|---|---|
value | string | required | The tab value this panel is associated with |
forceMount | boolean | false | Keep mounted in the DOM and toggle visibility via hidden + data-state |
Data attributes
| Attribute | Element | Values |
|---|---|---|
data-state | Trigger, Content | "active" / "inactive" |
data-orientation | Root, List, Trigger, Content | "horizontal" / "vertical" |
data-disabled | Trigger | Present when disabled |
data-hover / data-active / data-focus-visible | Trigger | Standard interactive states |
Trigger sets role="tab", aria-selected, aria-controls, and tabIndex={0} only for the active tab (roving tabindex). Content sets role="tabpanel", aria-labelledby, and tabIndex={0}. List sets role="tablist" and aria-orientation.
Accessibility
- Implements the WAI-ARIA tabs pattern with roving tabindex.
- Arrow keys navigate; disabled triggers are skipped automatically.
automaticactivation moves selection along with focus (most common). Usemanualfor tabs whose content is expensive to mount.
Keyboard Interactions
| Key | Description |
|---|---|
| ArrowRight / ArrowDown | Focus next trigger (axis depends on orientation). |
| ArrowLeft / ArrowUp | Focus previous trigger. |
| Home | Focus the first trigger. |
| End | Focus the last trigger. |
| Enter / Space | Activates the focused tab (manual mode only). |
| Tab | Moves focus into the active panel. |
Last updated on