Manage your account settings.

import { Tabs, TabsList, TabsTab, TabsPanel } from "@registry/components/ui/tabs";

export function TabsExample() {
  return (
    <div className="flex flex-col items-start justify-center">
      <Tabs defaultValue="account" className="w-full max-w-72">
        <TabsList>
          <TabsTab value="account">Account</TabsTab>
          <TabsTab value="password">Password</TabsTab>
          <TabsTab value="settings">Settings</TabsTab>
        </TabsList>
        <TabsPanel value="account">
          <p className={tabContentClassName}>Manage your account settings.</p>
        </TabsPanel>
        <TabsPanel value="password">
          <p className={tabContentClassName}>Change your password.</p>
        </TabsPanel>
        <TabsPanel value="settings">
          <p className={tabContentClassName}>Configure application settings.</p>
        </TabsPanel>
      </Tabs>
    </div>
  );
}

Examples

Underline variant

Use the underline variant for a minimal, border-based indicator style.

View your project overview and key metrics.

import { Tabs, TabsList, TabsTab, TabsPanel } from "@registry/components/ui/tabs";

export function TabsUnderlineExample() {
  return (
    <div className="flex flex-col items-start justify-center">
      <Tabs defaultValue="overview" className="w-full max-w-72">
        <TabsList variant="underline">
          <TabsTab value="overview">Overview</TabsTab>
          <TabsTab value="analytics">Analytics</TabsTab>
          <TabsTab value="reports">Reports</TabsTab>
        </TabsList>
        <TabsPanel value="overview">
          <p className={tabContentClassName}>View your project overview and key metrics.</p>
        </TabsPanel>
        <TabsPanel value="analytics">
          <p className={tabContentClassName}>Dive into detailed analytics and trends.</p>
        </TabsPanel>
        <TabsPanel value="reports">
          <p className={tabContentClassName}>Generate and download custom reports.</p>
        </TabsPanel>
      </Tabs>
    </div>
  );
}

Sizes

Available sizes: default, sm, lg.

Small size tabs.

Default size tabs.

Large size tabs.

import { Tabs, TabsList, TabsTab, TabsPanel } from "@registry/components/ui/tabs";

export function TabsSizesExample() {
  return (
    <div className="flex flex-col items-start gap-6">
      <Tabs defaultValue="sm" className="w-full max-w-72">
        <TabsList size="sm">
          <TabsTab value="sm">Small</TabsTab>
          <TabsTab value="sm2">Tab 2</TabsTab>
        </TabsList>
        <TabsPanel value="sm">
          <p className={tabContentClassName}>Small size tabs.</p>
        </TabsPanel>
        <TabsPanel value="sm2">
          <p className={tabContentClassName}>Another small tab.</p>
        </TabsPanel>
      </Tabs>

      <Tabs defaultValue="default" className="w-full max-w-72">
        <TabsList size="default">
          <TabsTab value="default">Default</TabsTab>
          <TabsTab value="default2">Tab 2</TabsTab>
        </TabsList>
        <TabsPanel value="default">
          <p className={tabContentClassName}>Default size tabs.</p>
        </TabsPanel>
        <TabsPanel value="default2">
          <p className={tabContentClassName}>Another default tab.</p>
        </TabsPanel>
      </Tabs>

      <Tabs defaultValue="lg" className="w-full max-w-72">
        <TabsList size="lg">
          <TabsTab value="lg">Large</TabsTab>
          <TabsTab value="lg2">Tab 2</TabsTab>
        </TabsList>
        <TabsPanel value="lg">
          <p className={tabContentClassName}>Large size tabs.</p>
        </TabsPanel>
        <TabsPanel value="lg2">
          <p className={tabContentClassName}>Another large tab.</p>
        </TabsPanel>
      </Tabs>
    </div>
  );
}

Vertical orientation

Set orientation="vertical" on Tabs to arrange tabs and panels side by side.

General settings for your application.

import { Tabs, TabsList, TabsTab, TabsPanel } from "@registry/components/ui/tabs";

export function TabsVerticalExample() {
  return (
    <div className="flex flex-col items-start justify-center">
      <Tabs defaultValue="general" orientation="vertical" className="w-full max-w-72">
        <TabsList>
          <TabsTab value="general">General</TabsTab>
          <TabsTab value="display">Display</TabsTab>
          <TabsTab value="advanced">Advanced</TabsTab>
        </TabsList>
        <TabsPanel value="general">
          <p className={tabContentClassName}>General settings for your application.</p>
        </TabsPanel>
        <TabsPanel value="display">
          <p className={tabContentClassName}>Customize display and appearance options.</p>
        </TabsPanel>
        <TabsPanel value="advanced">
          <p className={tabContentClassName}>Advanced configuration and experimental features.</p>
        </TabsPanel>
      </Tabs>
    </div>
  );
}

Installation

Copy the source code below into your project:

import { Tabs as BaseTabs } from "@base-ui/react/tabs";
import { cn } from "@registry/lib/utils";
import { cva } from "class-variance-authority";
import type { VariantProps } from "class-variance-authority";
import { createContext, useContext } from "react";

type TabsVariant = "default" | "underline";
type TabsSize = "default" | "sm" | "lg";

const TabsSizeContext = createContext<TabsSize>("default");

const tabsListVariants = cva(
  "relative z-0 flex items-center gap-x-0.5 data-[orientation=vertical]:h-fit data-[orientation=vertical]:flex-col data-[orientation=vertical]:gap-y-0.5",
  {
    compoundVariants: [
      { size: "sm", variant: "default", className: "p-1" },
      { size: "default", variant: "default", className: "p-1.5" },
      { size: "lg", variant: "default", className: "p-2" },
      {
        size: "sm",
        variant: "underline",
        className: "data-[orientation=horizontal]:py-0.5 data-[orientation=vertical]:px-0.5",
      },
      {
        size: "default",
        variant: "underline",
        className: "data-[orientation=horizontal]:py-1 data-[orientation=vertical]:px-1",
      },
      {
        size: "lg",
        variant: "underline",
        className: "data-[orientation=horizontal]:py-1.5 data-[orientation=vertical]:px-1.5",
      },
    ],
    defaultVariants: {
      size: "default",
      variant: "default",
    },
    variants: {
      size: {
        sm: "",
        default: "",
        lg: "",
      },
      variant: {
        default: "w-fit justify-center rounded-lg bg-muted",
        underline:
          "border-border data-[orientation=horizontal]:border-b data-[orientation=vertical]:border-l *:data-[slot=tabs-trigger]:hover:bg-muted",
      },
    },
  },
);

const tabIndicatorVariants = cva(
  "absolute transition-[width,height,translate] duration-200 ease-in-out data-[orientation=horizontal]:bottom-0 data-[orientation=horizontal]:left-0 data-[orientation=horizontal]:h-(--active-tab-height) data-[orientation=horizontal]:w-(--active-tab-width) data-[orientation=horizontal]:translate-x-(--active-tab-left) data-[orientation=horizontal]:-translate-y-(--active-tab-bottom) data-[orientation=vertical]:top-0 data-[orientation=vertical]:left-0 data-[orientation=vertical]:h-(--active-tab-height) data-[orientation=vertical]:w-(--active-tab-width) data-[orientation=vertical]:translate-x-(--active-tab-left) data-[orientation=vertical]:translate-y-(--active-tab-top)",
  {
    compoundVariants: [
      {
        size: "sm",
        variant: "underline",
        className: "data-[orientation=horizontal]:h-px data-[orientation=vertical]:w-px",
      },
      {
        size: "default",
        variant: "underline",
        className: "data-[orientation=horizontal]:h-0.5 data-[orientation=vertical]:w-0.5",
      },
      {
        size: "lg",
        variant: "underline",
        className: "data-[orientation=horizontal]:h-1 data-[orientation=vertical]:w-1",
      },
    ],
    defaultVariants: {
      size: "default",
      variant: "default",
    },
    variants: {
      size: {
        default: "",
        lg: "",
        sm: "",
      },
      variant: {
        default: "-z-1 rounded-md bg-popover",
        underline:
          "z-10 bg-accent data-[orientation=horizontal]:translate-y-px data-[orientation=vertical]:-translate-x-px",
      },
    },
  },
);

const tabsTabVariants = cva(
  "flex shrink-0 cursor-pointer items-center justify-center rounded-md font-medium whitespace-nowrap text-muted-foreground transition-[color,background-color,box-shadow] outline-none hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring data-active:text-foreground data-disabled:pointer-events-none data-disabled:opacity-50 data-[orientation=vertical]:w-full data-[orientation=vertical]:justify-start [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
  {
    defaultVariants: {
      size: "default",
    },
    variants: {
      size: {
        default: "gap-1.5 px-2 py-1.5 text-sm",
        lg: "gap-2 px-3 py-2 text-base",
        sm: "gap-1 px-1.5 py-1.5 text-xs",
      },
    },
  },
);

function Tabs({ className, ...props }: BaseTabs.Root.Props) {
  return (
    <BaseTabs.Root
      className={cn("flex flex-col gap-6 data-[orientation=vertical]:flex-row", className)}
      data-slot="tabs"
      {...props}
    />
  );
}

function TabsList({
  variant = "default",
  size = "default",
  className,
  children,
  ...props
}: BaseTabs.List.Props & {
  variant?: TabsVariant;
  size?: TabsSize;
}) {
  return (
    <BaseTabs.List
      className={cn(tabsListVariants({ className, size, variant }))}
      data-slot="tabs-list"
      {...props}
    >
      <TabsSizeContext.Provider value={size}>
        {children}
        <BaseTabs.Indicator
          className={cn(tabIndicatorVariants({ size, variant }))}
          data-slot="tab-indicator"
        />
      </TabsSizeContext.Provider>
    </BaseTabs.List>
  );
}

type TabsTabProps = BaseTabs.Tab.Props & VariantProps<typeof tabsTabVariants>;

function TabsTab({ className, size, ...props }: TabsTabProps) {
  const inheritedSize = useContext(TabsSizeContext);

  return (
    <BaseTabs.Tab
      className={cn(tabsTabVariants({ className, size: size ?? inheritedSize }))}
      data-slot="tabs-trigger"
      {...props}
    />
  );
}

function TabsPanel({ className, ...props }: BaseTabs.Panel.Props) {
  return (
    <BaseTabs.Panel
      className={cn("flex flex-1 flex-col gap-6 outline-none", className)}
      data-slot="tabs-content"
      {...props}
    />
  );
}

export { Tabs, TabsList, TabsTab, TabsTab as TabsTrigger, TabsPanel, TabsPanel as TabsContent };

API Reference

Tabs

This component does not add any props on top of Base UI Tabs.Root . See the Base UI docs for the full API reference.

TabsList

The TabsList component extends the Base UI Tabs.List props and adds the following:

PropTypeDefaultDescription
variant"default" | "underline""default"Visual style of the tabs list.
size"default" | "sm" | "lg""default"Size of the tabs and indicator.

TabsTab

The TabsTab component extends the Base UI Tabs.Tab props and adds the following:

PropTypeDefaultDescription
size"default" | "sm" | "lg"Override the tab size. Inherits from TabsList by default.

TabsPanel

This component does not add any props on top of Base UI Tabs.Panel . See the Base UI docs for the full API reference.