Tabs
Switch between related content in the same context.
navigationlayout
Preview
Tabs preview
Live · keyboard ready
Everything about this project, in one place.
When to use
- Peer views of the same object, such as Overview, Activity, and Settings.
- Panels with different heights, where the container should spring between them.
- Long tab sets that need to scroll horizontally with edge buttons.
When not to use
- Use segmented-control for a compact value toggle not tied to panels.
- Use accordion for stacked sections people read in order.
- Use liquid-tab-bar or morph-nav for app-level navigation between routes.
shadcn CLI
Also installs (1)
- manicat-foundation
Manual install(+)
registry.jsonjson
{
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
"name": "tabs",
"type": "registry:ui",
"title": "Tabs",
"description": "Switch between related content in the same context.",
"categories": [
"disclosure"
],
"dependencies": [
"@radix-ui/react-tabs",
"lucide-react",
"motion"
],
"registryDependencies": [
"https://manicat.viraza.net/r/manicat-foundation.json"
],
"files": [
{
"path": "registry/components/tabs/tabs.tsx",
"type": "registry:component",
"target": "@components/manicat/tabs/tabs.tsx"
},
{
"path": "registry/components/tabs/tabs.module.css",
"type": "registry:component",
"target": "@components/manicat/tabs/tabs.module.css"
}
],
"docs": "Docs and live preview: https://uiarc.dev/components/tabs",
"meta": {
"tier": "free",
"kind": "component",
"docs": "https://manicat.viraza.net/components/tabs",
"markdown": "https://uiarc.dev/components/tabs/markdown",
"tags": [
"navigation",
"layout"
]
}
}Usage
Install the component, then copy this into your app. Change the content and the props to fit your screen.
example.tsxtsx
"use client";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/manicat/tabs/tabs";
export function TabsExample() {
return (
<Tabs defaultValue="overview">
<TabsList>
<TabsTrigger value="overview">Overview</TabsTrigger>
<TabsTrigger value="activity">Activity</TabsTrigger>
<TabsTrigger value="settings">Settings</TabsTrigger>
</TabsList>
<TabsContent value="overview">Everything about this project, in one place.</TabsContent>
<TabsContent value="activity">Three deploys this week, one rollback.</TabsContent>
<TabsContent value="settings">Branches, domains and environment variables.</TabsContent>
</Tabs>
);
}
Examples
Real screens rather than isolated props. Switch to Code to copy a whole example into your project.
Project sections Tabs for a project page; panels cross-fade and the selection indicator glides.
Project sections
Tabs for a project page; panels cross-fade and the selection indicator glides. preview
Live · keyboard ready
3 deployments this week, 1 rollback on Tuesday.
project-sections-tabs-for-a-project-page-panels-cross-fade-and-the-selection-indicator-glides-.tsxtsx
"use client";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/manicat/tabs/tabs";
export function TabsProjectExample() {
return (
<Tabs defaultValue="deployments" className="w-full max-w-md">
<TabsList>
<TabsTrigger value="deployments">Deployments</TabsTrigger>
<TabsTrigger value="domains">Domains</TabsTrigger>
<TabsTrigger value="env">Environment</TabsTrigger>
</TabsList>
<TabsContent value="deployments">
<p className="py-4 text-sm text-(color:--text-muted)">3 deployments this week, 1 rollback on Tuesday.</p>
</TabsContent>
<TabsContent value="domains">
<p className="py-4 text-sm text-(color:--text-muted)">acme.com and www.acme.com, both verified.</p>
</TabsContent>
<TabsContent value="env">
<p className="py-4 text-sm text-(color:--text-muted)">12 variables across Production and Preview.</p>
</TabsContent>
</Tabs>
);
}
Keyboard interactions
| Keys | Action |
|---|---|
| ArrowLeft / ArrowRight | Moves between tabs and activates them. |
| Home / End | Jumps to the first or last tab. |
| Tab | Moves focus from the tab list into the active panel. |
Accessibility
- Radix provides role="tablist", role="tab", role="tabpanel", aria-selected, and aria-controls.
- The outgoing panel is made inert while it fades so it cannot take focus.
- Overflow scroll buttons are labelled "Scroll tabs left" and "Scroll tabs right"; give TabsList an aria-label.
Motion
- The selection pill glides between triggers on a morph spring, scoped to one Tabs instance.
- Panels slide 8px in the direction of travel while the height springs from the previous panel.
- Reduced motion swaps the pill instantly and crossfades panels in place without height animation.
Responsive behavior
- The tab list keeps max-width 100% and scrolls horizontally when triggers overflow, with scroll buttons at the edges.
- Focusing a tab scrolls it into view, so keyboard navigation works on narrow screens.
- Triggers keep a 5.5rem minimum width, so many tabs overflow sooner on mobile.
Performance
- ResizeObservers track list overflow and the active panel height; one per Tabs instance is cheap.
- The selection pill is a shared layout animation scoped to one Tabs; avoid dozens of tab sets on one screen.
Notes for AI
- Use for peer views of the same object. Use segmented-control for a compact value toggle that is not tied to panels, and accordion for stacked sections.
- Every TabsTrigger value needs a matching TabsContent. Long lists scroll horizontally on their own.