Skip to content

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

PropTypeDefaultDescription
defaultValuestringRequiredInitial active tab value
childrenReactNodeRequiredChild components (VerticalTabsList, VerticalTabContent)
classNamestring-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

PropTypeDefaultDescription
childrenReactNodeRequiredVerticalTabTrigger components
classNamestring-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

PropTypeDefaultDescription
valuestringRequiredUnique tab identifier
childrenReactNodeRequiredTab label text
iconReactNode-Optional icon (displayed on left)
descriptionstring-Optional description text (displayed below label)
classNamestring-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

PropTypeDefaultDescription
valuestringRequiredTab identifier (must match trigger value)
childrenReactNodeRequiredPanel content
classNamestring-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-200

Example

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
}

See Also