Manage your account settings.
Installation
pnpm dlx shadcn@latest add https://deltacomponents.dev/r/tabs.jsonUsage
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
export default function Example() {
return (
<Tabs defaultValue="account" className="w-[400px]">
<TabsList>
<TabsTrigger value="account">Account</TabsTrigger>
<TabsTrigger value="password">Password</TabsTrigger>
</TabsList>
<TabsContent value="account">
Make changes to your account here.
</TabsContent>
<TabsContent value="password">Change your password here.</TabsContent>
</Tabs>
)
}Examples
Underline Variant
The underline variant displays tabs with an animated underline indicator, perfect for navigation and section switching.
Manage your account settings.
Ghost Variant
Remove the background from the default variant tabs for a cleaner, more minimal appearance.
Manage your account settings.
Size Variants
Tabs come in three sizes: sm, default, and lg. Choose the size that best fits your layout.
Small
Manage your account settings.
Default
Manage your account settings.
Large
Manage your account settings.
With Icons
Enhance your tabs with icons for better visual communication and user experience.
Manage your account settings and preferences.
Entrance Animations
Control how tab content appears with customizable entrance animations. Set animate={true} on TabsContent to enable smooth transitions using CSS.
Manage your account settings.
Note: Animations are disabled by default for optimal performance. Enable them by setting animate={true} on individual TabsContent components when you need smooth transitions for lightweight content.
Tabs in Scroll Area
When you have many tabs that don't fit in the available space, wrap the TabsList in a ScrollArea to enable horizontal scrolling. This demo automatically scrolls the active tab into view when switching tabs.
Content for Tab 1. Click different tabs to see the active tab scroll into view automatically.
Performance Optimization
For tabs containing heavy content (large code blocks, images, complex components), use these optimization strategies to prevent animation stagger and improve performance:
Pre-render with forceMount
Set forceMount={true} to keep all tab content mounted in the DOM. This eliminates mounting/unmounting delays and ensures content is accessible to search engines and LLMs.
<Tabs defaultValue="tab1">
<TabsList>
<TabsTrigger value="tab1">Documentation</TabsTrigger>
<TabsTrigger value="tab2">Examples</TabsTrigger>
</TabsList>
<TabsContent value="tab1" forceMount={true}>
{/* Heavy content - always in DOM for crawlers */}
<ComplexCodeBlock />
</TabsContent>
<TabsContent value="tab2" forceMount={true}>
{/* Heavy content - always in DOM for crawlers */}
<LargeImageGallery />
</TabsContent>
</Tabs>CSS Content-Visibility Optimization
Combine forceMount with optimized={true} to enable CSS content-visibility optimization. This allows the browser to skip rendering off-screen content while keeping it in the DOM.
<TabsContent
value="tab1"
forceMount={true}
optimized={true}
intrinsicSize="auto 300px"
>
{/* Optimized heavy content */}
<HeavyComponent />
</TabsContent>When to use:
- forceMount only: Documentation sites with 2-5 tabs, SEO requirements
- forceMount + optimized: Modern browsers, heavy content, progressive enhancement
- Default behavior: Applications with many tabs (5+), memory-conscious scenarios
API Reference
Tabs
The root tabs component that provides context for all child components.
| Prop | Type | Default | Description |
|---|---|---|---|
| defaultValue | string | - | The value of the tab that should be active when initially rendered |
| value | string | - | The controlled value of the tab to activate |
| onValueChange | function | - | Event handler called when the value changes |
| variant | "default" | "underline" | "ghost" | "default" | Visual style variant of the tabs |
| size | "sm" | "small" | "default" | "lg" | "large" | "default" | Size of the tabs (both short and long forms accepted) |
| indicatorThickness | string | - | Override indicator thickness (e.g., "2px", "4px") |
| indicatorClassName | string | - | Override active indicator className (e.g., "bg-primary") |
| concentric | boolean | false | Use concentric border radius (outer = inner + padding) |
| className | string | - | Additional CSS classes |
TabsList
Container for the tab triggers with animated indicator support.
| Prop | Type | Default | Description |
|---|---|---|---|
| className | string | - | Additional CSS classes |
The TabsList component automatically inherits variant, size, indicatorThickness, indicatorClassName, and concentric from the parent Tabs component. For the underline variant, tabs align to the start; for default and ghost variants, they're centered.
TabsTrigger
Individual tab trigger button that activates a tab panel when clicked.
| Prop | Type | Default | Description |
|---|---|---|---|
| value | string | - | A unique value that associates the trigger with a content |
| icon | ReactNode | - | Icon to display alongside the label |
| disabled | boolean | false | When true, prevents the user from interacting with the tab |
| className | string | - | Additional CSS classes |
The trigger automatically displays the animated indicator when active using CSS transitions with requestAnimationFrame for smooth positioning.
TabsContent
Content panel associated with a tab trigger.
| Prop | Type | Default | Description |
|---|---|---|---|
| value | string | - | A unique value that associates the content with a trigger |
| forceMount | boolean | false | Forces the content to always be mounted in the DOM (hidden when inactive) |
| animate | boolean | false | Enable default opacity animation with ease-in-out |
| animateY | number | - | Set Y translation offset in pixels for entrance animation |
| animateOpacity | boolean | - | Set opacity animation - overrides animate when explicitly set |
| animationDuration | number | 250 | Animation duration in milliseconds |
| animationEasing | "ease" | "ease-in" | "ease-out" | "ease-in-out" | "linear" | string | varies | CSS timing function (default: "ease-out" for animateY, "ease-in-out" for animate) |
| optimized | boolean | false | Enable content-visibility CSS optimization for better performance |
| intrinsicSize | string | "auto 500px" | Set contain-intrinsic-size for content-visibility optimization |
| className | string | - | Additional CSS classes |
TabsFromArray
Utility component for rendering tabs from an array of tab items, useful when working with dynamic data.
| Prop | Type | Default | Description |
|---|---|---|---|
| tabs | TabItem[] | - | Array of tab items to render |
| defaultValue | string | tabs[0] | Initial active tab value |
| value | string | - | Controlled active tab value |
| onValueChange | function | - | Event handler called when the value changes |
| className | string | - | Additional CSS classes for Tabs |
| listClassName | string | - | Additional CSS classes for TabsList |
| triggerClassName | string | - | Additional CSS classes for each TabsTrigger |
| contentClassName | string | - | Additional CSS classes for each TabsContent |
| children | (tab) => ReactNode | - | Render function for tab content |
TabItem Type:
interface TabItem {
id: string
label: React.ReactNode
icon?: React.ReactNode
disabled?: boolean
}Features
- Animated Indicators: Smooth spring animations powered by Framer Motion
- Two Variants: Choose between default (background) and underline styles
- Three Sizes: Small, default, and large options for different layouts
- Icon Support: Add icons to your tabs for enhanced visual communication
- Keyboard Navigation: Full keyboard support for accessibility
- Disabled State: Disable individual tabs when needed
- Responsive: Works seamlessly across all screen sizes
- Dark Mode: Automatically adapts to your theme
Accessibility
- Uses Radix UI Tabs primitive for full accessibility compliance
- Supports keyboard navigation (Arrow keys, Home, End)
- Proper ARIA attributes for screen readers
- Focus management and visual indicators
Notes
- The animated indicator uses Framer Motion's
layoutIdfeature for smooth transitions - Tab content supports controlled and uncontrolled state management
- The underline variant tabs align to the start by default for better UX
- The default variant centers tabs within their container