Components
Tabs
A set of layered sections of content, known as tab panels, displayed one at a time.
Installation#
Install the dependencies
npm install class-variance-authority cn radix-uiCopy the source into your project
components/ui/tabs.tsx"use client"import * as React from "react"import { cva, type VariantProps } from "class-variance-authority"import { cn } from "cn"import { Tabs as TabsPrimitive } from "radix-ui"function Tabs({ className, orientation = "horizontal", ...props}: React.ComponentProps<typeof TabsPrimitive.Root>) { return ( <TabsPrimitive.Root data-slot="tabs" data-orientation={orientation} className={cn( "group/tabs flex gap-2 data-horizontal:flex-col", className )} {...props} /> )}const tabsListVariants = cva( "group/tabs-list inline-flex w-fit items-center justify-center gap-0.5 rounded-lg p-0.5 text-muted-foreground group-data-horizontal/tabs:h-9 group-data-vertical/tabs:h-fit group-data-vertical/tabs:flex-col data-[variant=line]:rounded-none", { variants: { variant: { default: "surface-sunken", line: "gap-1 bg-transparent", }, }, defaultVariants: { variant: "default", }, })function TabsList({ className, variant = "default", ...props}: React.ComponentProps<typeof TabsPrimitive.List> & VariantProps<typeof tabsListVariants>) { return ( <TabsPrimitive.List data-slot="tabs-list" data-variant={variant} className={cn(tabsListVariants({ variant }), className)} {...props} /> )}function TabsTrigger({ className, ...props}: React.ComponentProps<typeof TabsPrimitive.Trigger>) { return ( <TabsPrimitive.Trigger data-slot="tabs-trigger" className={cn( "relative inline-flex h-full flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-3 py-0.5 text-sm font-medium whitespace-nowrap text-muted-foreground transition-[color,background-color,box-shadow] duration-150 ease-out group-data-vertical/tabs:w-full group-data-vertical/tabs:justify-start hover:text-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1 focus-visible:outline-ring disabled:pointer-events-none disabled:opacity-50 has-data-[icon=inline-end]:pr-1 has-data-[icon=inline-start]:pl-1 dark:text-muted-foreground dark:hover:text-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", "group-data-[variant=line]/tabs-list:bg-transparent group-data-[variant=line]/tabs-list:data-active:bg-transparent dark:group-data-[variant=line]/tabs-list:data-active:border-transparent dark:group-data-[variant=line]/tabs-list:data-active:bg-transparent", "group-data-[variant=default]/tabs-list:data-active:bg-background group-data-[variant=default]/tabs-list:data-active:text-secondary-foreground group-data-[variant=default]/tabs-list:data-active:shadow-xs dark:group-data-[variant=default]/tabs-list:data-active:bg-white/10 dark:group-data-[variant=default]/tabs-list:data-active:text-foreground group-data-[variant=line]/tabs-list:data-active:text-foreground", "after:absolute after:bg-foreground after:opacity-0 after:transition-opacity group-data-horizontal/tabs:after:inset-x-0 group-data-horizontal/tabs:after:bottom-[-5px] group-data-horizontal/tabs:after:h-0.5 group-data-vertical/tabs:after:inset-y-0 group-data-vertical/tabs:after:-right-1 group-data-vertical/tabs:after:w-0.5 group-data-[variant=line]/tabs-list:data-active:after:opacity-100", className )} {...props} /> )}function TabsContent({ className, ...props}: React.ComponentProps<typeof TabsPrimitive.Content>) { return ( <TabsPrimitive.Content data-slot="tabs-content" className={cn("flex-1 text-sm outline-none", className)} {...props} /> )}export { Tabs, TabsList, TabsTrigger, TabsContent, tabsListVariants }Make sure the foundation is in place
Components read their colors, radius and surfaces from the tokens in
app/globals.css. See Theming.
Usage#
import { Tabs, TabsList, TabsTrigger, TabsContent,} from "@/components/ui/tabs"Examples#
Segmented
Full-width segmented control on a sunken track.
$24/month