Tabs
A set of layered sections of content, known as tab panels, displayed one at a time.
Installation
npx vayu-ui initnpx vayu-ui add tabsnpx vayu-ui add -t tabsUsage
Tabs Example
Account
Make changes to your account here. Click save when you're done.
Vertical Tabs
Profile Settings
Manage your personal information and preferences.
Disabled Tab
This tab is active and can be selected.
Tabs with Actions
Overview Section
Get a quick summary of your content and recent activity.
<h2 id="account-label">Account Settings</h2>
<Tabs defaultValue="account" className="mb-8">
<Tabs.List aria-labelledby="account-label" className="grid w-full grid-cols-2">
<Tabs.Trigger value="account">Account</Tabs.Trigger>
<Tabs.Trigger value="password">Password</Tabs.Trigger>
</Tabs.List>
<Tabs.Content value="account">
<p>Manage your account settings and preferences.</p>
</Tabs.Content>
<Tabs.Content value="password">
<p>Change your password and security settings.</p>
</Tabs.Content>
</Tabs>
<h3>Vertical</h3>
<Tabs defaultValue="profile" orientation="vertical" className="mb-8">
<Tabs.List aria-label="Settings navigation" className="min-w-50">
<Tabs.Trigger value="profile">Profile</Tabs.Trigger>
<Tabs.Trigger value="settings">Settings</Tabs.Trigger>
<Tabs.Trigger value="notifications">Notifications</Tabs.Trigger>
</Tabs.List>
<Tabs.Content value="profile" className="pl-4">
<p>Manage your personal information and preferences.</p>
</Tabs.Content>
<Tabs.Content value="settings" className="pl-4">
<p>Configure your application preferences and options.</p>
</Tabs.Content>
<Tabs.Content value="notifications" className="pl-4">
<p>Choose which notifications you want to receive.</p>
</Tabs.Content>
</Tabs>
<h3>With disabled tab</h3>
<Tabs defaultValue="enabled">
<Tabs.List aria-label="Tab options" className="grid w-full grid-cols-2">
<Tabs.Trigger value="enabled">Enabled Tab</Tabs.Trigger>
<Tabs.Trigger value="disabled" disabled>Disabled Tab</Tabs.Trigger>
</Tabs.List>
<Tabs.Content value="enabled">
<p>This tab is active and can be selected.</p>
</Tabs.Content>
</Tabs>Anatomy
<Tabs defaultValue="tab1">
<Tabs.List aria-label="Example tabs">
<Tabs.Trigger value="tab1">Tab 1</Tabs.Trigger>
<Tabs.Trigger value="tab2">Tab 2</Tabs.Trigger>
</Tabs.List>
<Tabs.Content value="tab1">Content 1</Tabs.Content>
<Tabs.Content value="tab2">Content 2</Tabs.Content>
</Tabs>Accessibility
- Keyboard navigation: Arrow keys move focus between tabs (left/right for horizontal, up/down for vertical). Home jumps to the first tab, End jumps to the last.
- Roving tabindex: Only the active tab has
tabIndex={0}; all others are-1. Arrow keys move focus and activate the tab simultaneously. - Activation: Pressing Enter or Space on a focused trigger activates the associated tab panel.
- Disabled tabs: Skipped during keyboard navigation and marked with
aria-disabled="true". - Auto-focus: When
autoFocusis set onTabs, focus moves to the tab panel when it becomes active.
ARIA attributes
| Element | Attribute | Value |
|---|---|---|
| Tabs.List | role | tablist |
| Tabs.List | aria-orientation | "horizontal" or "vertical" |
| Tabs.List | aria-label / aria-labelledby | Accessible name for the tab list |
| Tabs.Trigger | role | tab |
| Tabs.Trigger | aria-selected | true or false |
| Tabs.Trigger | aria-controls | ID of the associated tab panel |
| Tabs.Trigger | aria-disabled | true when disabled |
| Tabs.Content | role | tabpanel |
| Tabs.Content | aria-labelledby | ID of the associated tab trigger |
Screen reader behavior
- Screen readers announce
Tabs.Listas a "tab list" using the providedaria-labeloraria-labelledby. - Each trigger is announced as a "tab" with its label text and selection state (e.g., "Account, tab, selected" or "Password, tab").
- When a tab is activated, the associated panel is announced as a "tab panel" linked to the trigger via
aria-labelledby. - Disabled triggers are announced as unavailable and are not included in the tab navigation sequence.
- Switching tabs moves the reading cursor to the new panel content automatically.
Component Folder Structure
Tab/
├── Tab.tsx # Context provider + compound component wiring
├── TabsList.tsx # Tablist container with keyboard navigation
├── TabsTrigger.tsx # Tab trigger button
├── TabsContent.tsx # Tab panel content
├── hooks.ts # TabsContext + useTabsContext hook
├── types.ts # All interfaces and type exports
├── index.ts # Public API
└── README.md # Internal documentationProps
Tabs
| Prop | Type | Default | Description |
|---|---|---|---|
defaultValue | string | - | The value of the tab to activate by default (uncontrolled). |
value | string | - | The controlled value of the active tab. |
onValueChange | (value: string) => void | - | Called when the active tab changes. |
orientation | "horizontal" | "vertical" | "horizontal" | Layout direction of the tab list. |
autoFocus | boolean | false | Move focus to the tab panel when activated. |
className | string | - | Additional CSS classes. |
children | ReactNode | - | Tabs.List and Tabs.Content components. |
Tabs.List
| Prop | Type | Default | Description |
|---|---|---|---|
aria-label | string | - | Accessible name for the tab list. |
aria-labelledby | string | - | ID of an element that labels the tab list. |
className | string | - | Additional CSS classes. |
children | ReactNode | - | Tabs.Trigger components. |
Tabs.Trigger
| Prop | Type | Default | Description |
|---|---|---|---|
value | string | - | Unique value matching a Tabs.Content. |
disabled | boolean | false | Prevents the tab from being activated. |
className | string | - | Additional CSS classes. |
children | ReactNode | - | Label content. |
Tabs.Content
| Prop | Type | Default | Description |
|---|---|---|---|
value | string | - | Unique value matching a Tabs.Trigger. |
forceMount | boolean | false | Keep the panel mounted when inactive (hidden with hidden attribute). |
className | string | - | Additional CSS classes. |
children | ReactNode | - | Panel content. |