YA Tabs
A tabs component with default and line types for organizing content into sections
The YaTabs component provides a way to organize content into multiple panels that can be switched between. It supports two visual types (default and line), stretch labels mode, and optional icons on tab triggers.
Quick Start
pnpm dlx shadcn@latest add @yavendio/ya-tabsnpx shadcn@latest add @yavendio/ya-tabsyarn dlx shadcn@latest add @yavendio/ya-tabsimport { YaTabs, YaTabsList, YaTabsTrigger, YaTabsContent } from '@/components/ui/ya-tabs'
export default function Example() {
return (
<YaTabs defaultValue="tab1">
<YaTabsList>
<YaTabsTrigger value="tab1">Tab 1</YaTabsTrigger>
<YaTabsTrigger value="tab2">Tab 2</YaTabsTrigger>
<YaTabsTrigger value="tab3">Tab 3</YaTabsTrigger>
</YaTabsList>
<YaTabsContent value="tab1">Content for Tab 1</YaTabsContent>
<YaTabsContent value="tab2">Content for Tab 2</YaTabsContent>
<YaTabsContent value="tab3">Content for Tab 3</YaTabsContent>
</YaTabs>
)
}Types
YaTabs comes with two visual types for different use cases:
| Type | Description | Usage |
|---|---|---|
default | Contained background with rounded corners | Settings panels, content sections |
line | Minimal with bottom border indicator | Navigation, minimal UIs |
Default Type
Line Type
Default Type
A contained style with gray background and shadow on the active tab.
<YaTabs type="default" defaultValue="tab1">
<YaTabsList>
<YaTabsTrigger value="tab1">Overview</YaTabsTrigger>
<YaTabsTrigger value="tab2">Settings</YaTabsTrigger>
<YaTabsTrigger value="tab3">Analytics</YaTabsTrigger>
</YaTabsList>
<YaTabsContent value="tab1">Overview content</YaTabsContent>
<YaTabsContent value="tab2">Settings content</YaTabsContent>
<YaTabsContent value="tab3">Analytics content</YaTabsContent>
</YaTabs>Features:
- Gray background container with rounded corners
- Selected tab has white background with subtle shadow
- Unselected tabs have no background
Line Type
A minimal style with underline indicator for the active tab.
<YaTabs type="line" defaultValue="tab1">
<YaTabsList>
<YaTabsTrigger value="tab1">Overview</YaTabsTrigger>
<YaTabsTrigger value="tab2">Settings</YaTabsTrigger>
<YaTabsTrigger value="tab3">Analytics</YaTabsTrigger>
</YaTabsList>
<YaTabsContent value="tab1">Overview content</YaTabsContent>
<YaTabsContent value="tab2">Settings content</YaTabsContent>
<YaTabsContent value="tab3">Analytics content</YaTabsContent>
</YaTabs>Features:
- No background container
- Selected tab has a bottom border
- Clean, minimal appearance
Stretch Labels
Use the stretchLabels prop to make tabs fill the available width.
Without Stretch
With Stretch
// Without stretch - tabs take only the space needed
<YaTabs type="default" stretchLabels={false} defaultValue="tab1">
<YaTabsList>
<YaTabsTrigger value="tab1">Tab 1</YaTabsTrigger>
<YaTabsTrigger value="tab2">Tab 2</YaTabsTrigger>
<YaTabsTrigger value="tab3">Tab 3</YaTabsTrigger>
</YaTabsList>
</YaTabs>
// With stretch - tabs expand to fill width
<YaTabs type="default" stretchLabels={true} defaultValue="tab1">
<YaTabsList>
<YaTabsTrigger value="tab1">Tab 1</YaTabsTrigger>
<YaTabsTrigger value="tab2">Tab 2</YaTabsTrigger>
<YaTabsTrigger value="tab3">Tab 3</YaTabsTrigger>
</YaTabsList>
</YaTabs>Stretch Labels with Line Type
<YaTabs type="line" stretchLabels={true} defaultValue="tab1">
<YaTabsList>
<YaTabsTrigger value="tab1">Overview</YaTabsTrigger>
<YaTabsTrigger value="tab2">Settings</YaTabsTrigger>
<YaTabsTrigger value="tab3">Analytics</YaTabsTrigger>
</YaTabsList>
<YaTabsContent value="tab1">Overview content</YaTabsContent>
<YaTabsContent value="tab2">Settings content</YaTabsContent>
<YaTabsContent value="tab3">Analytics content</YaTabsContent>
</YaTabs>Icons
Add icons to the left or right of tab text:
import { Home, Settings, BarChart } from 'lucide-react'
<YaTabs type="default" defaultValue="home">
<YaTabsList>
<YaTabsTrigger value="home" leftIcon={<Home />}>
Home
</YaTabsTrigger>
<YaTabsTrigger value="settings" leftIcon={<Settings />}>
Settings
</YaTabsTrigger>
<YaTabsTrigger value="analytics" rightIcon={<BarChart />}>
Analytics
</YaTabsTrigger>
</YaTabsList>
<YaTabsContent value="home">Home content</YaTabsContent>
<YaTabsContent value="settings">Settings content</YaTabsContent>
<YaTabsContent value="analytics">Analytics content</YaTabsContent>
</YaTabs>Icons are automatically sized to 12px to match the design system specifications.
States
Controlled State
Use the value and onValueChange props for controlled behavior:
Active tab: tab1
'use client'
import { useState } from 'react'
import { YaTabs, YaTabsList, YaTabsTrigger, YaTabsContent } from '@/components/ui/ya-tabs'
export default function ControlledTabs() {
const [activeTab, setActiveTab] = useState('tab1')
return (
<>
<p>Active tab: {activeTab}</p>
<YaTabs value={activeTab} onValueChange={setActiveTab}>
<YaTabsList>
<YaTabsTrigger value="tab1">Tab 1</YaTabsTrigger>
<YaTabsTrigger value="tab2">Tab 2</YaTabsTrigger>
</YaTabsList>
<YaTabsContent value="tab1">Content 1</YaTabsContent>
<YaTabsContent value="tab2">Content 2</YaTabsContent>
</YaTabs>
</>
)
}Disabled Tabs
Disable individual tabs using the disabled prop:
<YaTabs defaultValue="tab1">
<YaTabsList>
<YaTabsTrigger value="tab1">Available</YaTabsTrigger>
<YaTabsTrigger value="tab2" disabled>
Coming Soon
</YaTabsTrigger>
<YaTabsTrigger value="tab3">Active</YaTabsTrigger>
</YaTabsList>
<YaTabsContent value="tab1">Available content</YaTabsContent>
<YaTabsContent value="tab2">Coming soon content</YaTabsContent>
<YaTabsContent value="tab3">Active content</YaTabsContent>
</YaTabs>Examples
Navigation Tabs
Overview
Welcome to your dashboard.
<YaTabs type="line" defaultValue="overview" className="w-full">
<YaTabsList>
<YaTabsTrigger value="overview">Overview</YaTabsTrigger>
<YaTabsTrigger value="documents">Documents</YaTabsTrigger>
<YaTabsTrigger value="settings">Settings</YaTabsTrigger>
</YaTabsList>
<YaTabsContent value="overview">
<h2>Overview</h2>
<p>Welcome to your dashboard.</p>
</YaTabsContent>
<YaTabsContent value="documents">
<h2>Documents</h2>
<p>Your documents will appear here.</p>
</YaTabsContent>
<YaTabsContent value="settings">
<h2>Settings</h2>
<p>Manage your account settings.</p>
</YaTabsContent>
</YaTabs>Settings Panel
Profile settings content
import { User, Lock, Bell, CreditCard } from 'lucide-react'
<YaTabs type="default" stretchLabels={true} defaultValue="profile">
<YaTabsList>
<YaTabsTrigger value="profile" leftIcon={<User />}>
Profile
</YaTabsTrigger>
<YaTabsTrigger value="security" leftIcon={<Lock />}>
Security
</YaTabsTrigger>
<YaTabsTrigger value="notifications" leftIcon={<Bell />}>
Notifications
</YaTabsTrigger>
<YaTabsTrigger value="billing" leftIcon={<CreditCard />}>
Billing
</YaTabsTrigger>
</YaTabsList>
<YaTabsContent value="profile">Profile settings content</YaTabsContent>
<YaTabsContent value="security">Security settings content</YaTabsContent>
<YaTabsContent value="notifications">Notification preferences</YaTabsContent>
<YaTabsContent value="billing">Billing information</YaTabsContent>
</YaTabs>Compact Tabs
<YaTabs type="default" defaultValue="all">
<YaTabsList>
<YaTabsTrigger value="all">All</YaTabsTrigger>
<YaTabsTrigger value="active">Active</YaTabsTrigger>
<YaTabsTrigger value="pending">Pending</YaTabsTrigger>
<YaTabsTrigger value="completed">Completed</YaTabsTrigger>
</YaTabsList>
</YaTabs>Props
YaTabs
| Prop | Type | Default | Description |
|---|---|---|---|
type | 'default' | 'line' | 'default' | Visual style type |
stretchLabels | boolean | false | Whether tabs stretch to fill width |
defaultValue | string | - | Initially active tab (uncontrolled) |
value | string | - | Active tab (controlled) |
onValueChange | (value: string) => void | - | Callback when active tab changes |
orientation | 'horizontal' | 'vertical' | 'horizontal' | Tab orientation |
className | string | - | Additional classes |
YaTabsList
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | - | Additional classes |
YaTabsTrigger
| Prop | Type | Default | Description |
|---|---|---|---|
value | string | required | Unique value for the tab |
leftIcon | ReactNode | - | Icon on the left |
rightIcon | ReactNode | - | Icon on the right |
disabled | boolean | false | Disable the tab |
className | string | - | Additional classes |
YaTabsContent
| Prop | Type | Default | Description |
|---|---|---|---|
value | string | required | Value matching a trigger |
forceMount | boolean | false | Keep content mounted when hidden |
className | string | - | Additional classes |
Accessibility
<YaTabs defaultValue="tab1">
<YaTabsList aria-label="Account settings">
<YaTabsTrigger value="tab1">Profile</YaTabsTrigger>
<YaTabsTrigger value="tab2">Security</YaTabsTrigger>
</YaTabsList>
<YaTabsContent value="tab1">Profile settings</YaTabsContent>
<YaTabsContent value="tab2">Security settings</YaTabsContent>
</YaTabs>Best Practices
| Do | Don't |
|---|---|
Use default type for contained sections | Line type for dense settings panels |
Use line type for navigation | Default type for minimal UIs |
Enable stretchLabels for primary navigation | Stretch labels for auxiliary tabs |
| Use concise, descriptive labels | Vague labels like "Tab 1", "Tab 2" |
Provide aria-label on YaTabsList | Missing accessibility attributes |
| Use icons consistently (all tabs or none) | Mix icon placement styles |
TypeScript
import { type VariantProps } from 'class-variance-authority'
import { yaTabsListVariants, yaTabsTriggerVariants } from '@/components/ui/ya-tabs'
// Extract variant types
type TabsListType = VariantProps<typeof yaTabsListVariants>['type']
type TriggerType = VariantProps<typeof yaTabsTriggerVariants>['type']
// Use in your components
interface MyComponentProps {
tabType?: TabsListType
}