Tabs

Switch between related content in the same context.

navigationlayout
Preview
Tabs preview
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

3 deployments this week, 1 rollback on Tuesday.

Keyboard interactions

KeysAction
ArrowLeft / ArrowRightMoves between tabs and activates them.
Home / EndJumps to the first or last tab.
TabMoves 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.