Appearance
VerticalTabs API
Complete type definitions and prop reference for the VerticalTabs component system.
VerticalTabs (Root)
Root container component that manages tab state.
Import
tsx
import { VerticalTabs } from '@/shared/ui/components/vertical-tabs/VerticalTabs'Props
VerticalTabsProps
| Prop | Type | Default | Description |
|---|---|---|---|
defaultValue | string | Required | Initial active tab value |
children | ReactNode | Required | Child components (VerticalTabsList, VerticalTabContent) |
className | string | - | Additional CSS classes for root container |
onChange | (value: string) => void | - | Callback when active tab changes |
Example
tsx
<VerticalTabs
defaultValue="profile"
onChange={(value) => console.log('Active tab:', value)}
className="max-w-5xl mx-auto"
>
{/* VerticalTabsList and VerticalTabContent */}
</VerticalTabs>VerticalTabsList
Container for tab triggers (left sidebar).
Import
tsx
import { VerticalTabsList } from '@/shared/ui/components/vertical-tabs/VerticalTabs'Props
VerticalTabsListProps
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | Required | VerticalTabTrigger components |
className | string | - | Additional CSS classes |
Features
- ARIA role:
tablist - Orientation:
vertical - Border: Right border to separate from content
- Flex layout: Vertical stack with gap
Example
tsx
<VerticalTabsList className="w-64 bg-muted/30 rounded-lg p-2">
<VerticalTabTrigger value="tab1">Tab 1</VerticalTabTrigger>
<VerticalTabTrigger value="tab2">Tab 2</VerticalTabTrigger>
</VerticalTabsList>VerticalTabTrigger
Individual tab button.
Import
tsx
import { VerticalTabTrigger } from '@/shared/ui/components/vertical-tabs/VerticalTabs'Props
VerticalTabTriggerProps
| Prop | Type | Default | Description |
|---|---|---|---|
value | string | Required | Unique tab identifier |
children | ReactNode | Required | Tab label text |
icon | ReactNode | - | Optional icon (displayed on left) |
description | string | - | Optional description text (displayed below label) |
className | string | - | Additional CSS classes |
Features
- ARIA role:
tab - ARIA selected: Indicates active state
- ARIA controls: Links to content panel
- Keyboard accessible: Focus and activation support
- Active state: Visual feedback with border and background
- Hover state: Subtle background change
States
Active:
- Primary background (
bg-primary/10) - Primary text color
- Left border accent
- Semibold font weight
Inactive:
- Muted text color
- Hover background
- Regular font weight
Example
tsx
import { User } from 'lucide-react'
<VerticalTabTrigger
value="profile"
icon={<User className="h-4 w-4" />}
description="Manage your personal information"
className="custom-class"
>
Profile
</VerticalTabTrigger>VerticalTabContent
Content panel for each tab.
Import
tsx
import { VerticalTabContent } from '@/shared/ui/components/vertical-tabs/VerticalTabs'Props
VerticalTabContentProps
| Prop | Type | Default | Description |
|---|---|---|---|
value | string | Required | Tab identifier (must match trigger value) |
children | ReactNode | Required | Panel content |
className | string | - | Additional CSS classes |
Features
- ARIA role:
tabpanel - ARIA labelledby: Links to tab trigger
- Conditional rendering: Only renders when active
- Animation: Fade in and slide from right
- Flex layout: Takes remaining space
Animation
css
/* Tailwind classes applied */
animate-in fade-in-0 slide-in-from-right-2 duration-200Example
tsx
<VerticalTabContent
value="profile"
className="bg-card rounded-lg p-6"
>
<h2 className="text-2xl font-bold mb-4">Profile Settings</h2>
<ProfileForm />
</VerticalTabContent>useVerticalTabs Hook
Access tab context from child components.
Import
tsx
import { useVerticalTabs } from '@/shared/ui/components/vertical-tabs/useVerticalTabs'Returns
ts
interface VerticalTabsContextValue {
activeTab: string
setActiveTab: (tab: string) => void
}Example
tsx
function CustomTabComponent() {
const { activeTab, setActiveTab } = useVerticalTabs()
return (
<div>
<p>Current tab: {activeTab}</p>
<button onClick={() => setActiveTab('profile')}>
Go to Profile
</button>
</div>
)
}Complete Example
tsx
import {
VerticalTabs,
VerticalTabsList,
VerticalTabTrigger,
VerticalTabContent,
} from '@/shared/ui/components/vertical-tabs/VerticalTabs'
import { User, Settings, Shield, Bell } from 'lucide-react'
function SettingsPage() {
const handleTabChange = (value: string) => {
// Track analytics
console.log('Tab changed to:', value)
}
return (
<div className="container max-w-6xl py-8">
<h1 className="text-3xl font-bold mb-8">Settings</h1>
<VerticalTabs
defaultValue="profile"
onChange={handleTabChange}
className="gap-8"
>
<VerticalTabsList className="w-64">
<VerticalTabTrigger
value="profile"
icon={<User className="h-4 w-4" />}
description="Personal information and preferences"
>
Profile
</VerticalTabTrigger>
<VerticalTabTrigger
value="account"
icon={<Settings className="h-4 w-4" />}
description="Account settings and preferences"
>
Account
</VerticalTabTrigger>
<VerticalTabTrigger
value="security"
icon={<Shield className="h-4 w-4" />}
description="Password and authentication"
>
Security
</VerticalTabTrigger>
<VerticalTabTrigger
value="notifications"
icon={<Bell className="h-4 w-4" />}
description="Email and push notifications"
>
Notifications
</VerticalTabTrigger>
</VerticalTabsList>
<VerticalTabContent value="profile">
<div className="space-y-6">
<h2 className="text-2xl font-bold">Profile Settings</h2>
{/* Profile form */}
</div>
</VerticalTabContent>
<VerticalTabContent value="account">
<div className="space-y-6">
<h2 className="text-2xl font-bold">Account Settings</h2>
{/* Account form */}
</div>
</VerticalTabContent>
<VerticalTabContent value="security">
<div className="space-y-6">
<h2 className="text-2xl font-bold">Security Settings</h2>
{/* Security form */}
</div>
</VerticalTabContent>
<VerticalTabContent value="notifications">
<div className="space-y-6">
<h2 className="text-2xl font-bold">Notification Settings</h2>
{/* Notifications form */}
</div>
</VerticalTabContent>
</VerticalTabs>
</div>
)
}Styling
Default Styles
VerticalTabs (Root):
tsx
className="flex gap-6"VerticalTabsList:
tsx
className="flex flex-col gap-1 shrink-0 border-r border-border/50 pr-4"VerticalTabTrigger (Active):
tsx
className="bg-primary/10 text-primary border-l-2 border-primary -ml-[2px]"VerticalTabTrigger (Inactive):
tsx
className="text-muted-foreground hover:bg-muted/50 hover:text-foreground"VerticalTabContent:
tsx
className="flex-1 min-w-0 animate-in fade-in-0 slide-in-from-right-2 duration-200"Customization
Override default styles with className prop:
tsx
<VerticalTabs className="max-w-7xl mx-auto">
<VerticalTabsList className="w-72 bg-card rounded-lg p-3">
<VerticalTabTrigger
value="tab1"
className="rounded-md hover:bg-accent"
>
Tab 1
</VerticalTabTrigger>
</VerticalTabsList>
<VerticalTabContent
value="tab1"
className="bg-muted/30 rounded-lg p-8"
>
Content
</VerticalTabContent>
</VerticalTabs>Accessibility
ARIA Attributes
VerticalTabsList:
role="tablist"aria-orientation="vertical"
VerticalTabTrigger:
role="tab"aria-selected={isActive}aria-controls="panel-{value}"
VerticalTabContent:
role="tabpanel"id="panel-{value}"aria-labelledby="tab-{value}"
Keyboard Navigation
- Tab: Move focus to/from tab list
- Arrow Up/Down: Navigate between tabs (native button behavior)
- Enter/Space: Activate focused tab
- Focus visible: Clear focus ring on keyboard navigation
Type Definitions
ts
// Root component
interface VerticalTabsProps {
defaultValue: string
children: React.ReactNode
className?: string
onChange?: (value: string) => void
}
// Tab list
interface VerticalTabsListProps {
children: React.ReactNode
className?: string
}
// Tab trigger
interface VerticalTabTriggerProps {
value: string
children: React.ReactNode
icon?: React.ReactNode
description?: string
className?: string
}
// Tab content
interface VerticalTabContentProps {
value: string
children: React.ReactNode
className?: string
}
// Context
interface VerticalTabsContextValue {
activeTab: string
setActiveTab: (tab: string) => void
}