Tabs
Accessible tab interface with keyboard navigation and automatic or manual activation.
Tabs
The Tabs component provides a fully accessible tabbed interface following WAI-ARIA patterns. It supports controlled and uncontrolled modes, arrow-key navigation, and both automatic (select on focus) and manual (select on click) activation modes.
Tabs requires sub-components: TabsList for the tab buttons, TabsTrigger for individual tabs, and TabsContent for panel content.
Features
- Controlled/uncontrolled modes
- Automatic (focus-selects) or manual (click-to-select) activation
- Arrow-key navigation with roving tab index
- Horizontal or vertical orientation
- RTL support
- Full ARIA tablist/tab/tabpanel semantics
Usage
import { Tabs, TabsList, TabsTrigger, TabsContent } from '@loke/ui/tabs';
export default function Example() {
return (
<Tabs defaultValue="tab1">
<TabsList>
<TabsTrigger value="tab1">Tab 1</TabsTrigger>
<TabsTrigger value="tab2">Tab 2</TabsTrigger>
<TabsTrigger value="tab3">Tab 3</TabsTrigger>
</TabsList>
<TabsContent value="tab1">Content for tab 1</TabsContent>
<TabsContent value="tab2">Content for tab 2</TabsContent>
<TabsContent value="tab3">Content for tab 3</TabsContent>
</Tabs>
);
}Props
Tabs
Prop
Type
TabsList
Prop
Type
TabsTrigger
Prop
Type
TabsContent
Prop
Type
Examples
Basic tabs with active styling
Overview: A summary of key product information and highlights.
Controlled tabs
Manage your account details and preferences.
Active tab: account
Vertical orientation
General application settings and display preferences.
Basic horizontal tabs
<Tabs defaultValue="overview">
<TabsList className="border-b">
<TabsTrigger value="overview" className="px-4 py-2">Overview</TabsTrigger>
<TabsTrigger value="details" className="px-4 py-2">Details</TabsTrigger>
<TabsTrigger value="reviews" className="px-4 py-2">Reviews</TabsTrigger>
</TabsList>
<div className="mt-4">
<TabsContent value="overview" className="text-sm text-gray-700">Overview panel content</TabsContent>
<TabsContent value="details" className="text-sm text-gray-700">Details panel content</TabsContent>
<TabsContent value="reviews" className="text-sm text-gray-700">Reviews panel content</TabsContent>
</div>
</Tabs>Vertical tabs
<Tabs defaultValue="settings" orientation="vertical" className="flex gap-4">
<TabsList className="flex flex-col w-32 border-r">
<TabsTrigger value="settings" className="justify-start px-3 py-2">Settings</TabsTrigger>
<TabsTrigger value="security" className="justify-start px-3 py-2">Security</TabsTrigger>
<TabsTrigger value="notifications" className="justify-start px-3 py-2">Notifications</TabsTrigger>
</TabsList>
<div className="flex-1">
<TabsContent value="settings">Settings panel</TabsContent>
<TabsContent value="security">Security panel</TabsContent>
<TabsContent value="notifications">Notifications panel</TabsContent>
</div>
</Tabs>Manual activation (click to select)
<Tabs defaultValue="tab1" activationMode="manual">
<TabsList>
<TabsTrigger value="tab1">Tab 1</TabsTrigger>
<TabsTrigger value="tab2">Tab 2</TabsTrigger>
</TabsList>
<TabsContent value="tab1">Click to select tabs (not just arrow focus)</TabsContent>
<TabsContent value="tab2">This is tab 2</TabsContent>
</Tabs>Keyboard Navigation
- Arrow Left/Right (horizontal) or Arrow Up/Down (vertical): Move focus between tabs
- Home/End: Jump to first/last tab
- Tab: Move to next focusable element outside the tabs
- Space/Enter (manual mode): Select the focused tab
In automatic mode, the focused tab is selected immediately. In manual mode, you must press Space/Enter to select.
Accessibility
- TabsList has
role="tablist"andaria-orientation - Triggers have
role="tab",aria-selected, andaria-controls - Content panels have
role="tabpanel",aria-labelledby, andtabindex="0" - Disabled triggers have
aria-disabled="true" - Only one trigger is in the tab order at a time (roving tab index)
Best practices
- Use
activationMode="automatic"for quick tabs (default); use"manual"for tabs with significant content or complex state - Provide clear, concise tab labels
- Don't disable tabs unless necessary; explain why if disabled
- Keep content organized logically; avoid too many tabs (5–7 is a good limit)
- Test keyboard navigation with screen readers to ensure tab labels and panel association is clear