UI
Tabs
A collection of content layers called tab panels, shown individually.
You have 60 days from the time we've shipped your order to return any part of it to us for a refund, provided it is still in its original, unused condition: we do not accept returns of used items.
No return authorization (RMA) is required. If you are within the United States, a pre-paid shipping label will be generated. For direct returns, a flat fee of $10 is deducted from your return for shipping and processing costs.
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/Tabs"
export const TabsHero = () => ( <Tabs defaultValue="tab1"> <TabsList> <TabsTrigger value="tab1">Returns</TabsTrigger> <TabsTrigger value="tab2">Shipping</TabsTrigger> </TabsList> <div className="ml-2 mt-4"> <TabsContent value="tab1" className="space-y-2 text-sm leading-7 text-gray-600 dark:text-gray-500" > <p> You have 60 days from the time we've shipped your order to return any part of it to us for a refund, provided it is still in its original, unused condition: we do not accept returns of used items. </p> <p> No return authorization (RMA) is required. If you are within the United States, a pre-paid shipping label will be generated. For direct returns, a flat fee of $10 is deducted from your return for shipping and processing costs. </p> </TabsContent> <TabsContent value="tab2" className="space-y-2 text-sm leading-7 text-gray-600 dark:text-gray-500" > <p> We ship worldwide via UPS Expedited. We offer flat rate shipping to customers in Canada ($30), the EU, Japan, and Singapore ($45–$65+), and Australia ($65). Note that most brokerage fees are included in the price of UPS Expedited shipping, with the exception of a possible $10 fee assessed in Canada only if prior arrangements to pay for duties and taxes are not made (see next question and answer). </p> <p> Outside of the United States, tariffs, duties, and taxes are the responsibility of the customer and are usually paid at time of delivery. </p> </TabsContent> </div> </Tabs>);
Installation
npm install @radix-ui/react-tabs
- Copy and paste the code into your project’s component directory. Do not forget to update the import paths.
// Tremor Tabs [v0.1.0] import React from "react"import * as TabsPrimitives from "@radix-ui/react-tabs" import { cx, focusRing } from "@/lib/utils" const Tabs = ( props: Omit< React.ComponentPropsWithoutRef<typeof TabsPrimitives.Root>, "orientation" >,) => { return <TabsPrimitives.Root tremor-id="tremor-raw" {...props} />} Tabs.displayName = "Tabs" type TabsListVariant = "line" | "solid" const TabsListVariantContext = React.createContext<TabsListVariant>("line") interface TabsListProps extends React.ComponentPropsWithoutRef<typeof TabsPrimitives.List> { variant?: TabsListVariant} const variantStyles: Record<TabsListVariant, string> = { line: cx( // base "flex items-center justify-start border-b", // border color "border-gray-200 dark:border-gray-800", ), solid: cx( // base "inline-flex items-center justify-center rounded-md p-1", // background color "bg-gray-100 dark:bg-gray-900", ),} const TabsList = React.forwardRef< React.ElementRef<typeof TabsPrimitives.List>, TabsListProps>(({ className, variant = "line", children, ...props }, forwardedRef) => ( <TabsPrimitives.List ref={forwardedRef} className={cx(variantStyles[variant], className)} {...props} > <TabsListVariantContext.Provider value={variant}> {children} </TabsListVariantContext.Provider> </TabsPrimitives.List>)) TabsList.displayName = "TabsList" function getVariantStyles(tabVariant: TabsListVariant) { switch (tabVariant) { case "line": return cx( // base "-mb-px items-center justify-center whitespace-nowrap border-b-2 border-transparent px-3 pb-2 text-sm font-medium transition-all", // text color "text-gray-500 dark:text-gray-500", // hover "hover:text-gray-700 hover:dark:text-gray-400", // border hover "hover:border-gray-300 hover:dark:border-gray-400", // selected "data-[state=active]:border-blue-500 data-[state=active]:text-blue-500", "data-[state=active]:dark:border-blue-500 data-[state=active]:dark:text-blue-500", // disabled "data-[disabled]:pointer-events-none", "data-[disabled]:text-gray-300 data-[disabled]:dark:text-gray-700", ) case "solid": return cx( // base "inline-flex items-center justify-center whitespace-nowrap rounded px-3 py-1 text-sm font-medium ring-1 ring-inset transition-all", // text color "text-gray-500 dark:text-gray-400", // hover "hover:text-gray-700 hover:dark:text-gray-200", // ring "ring-transparent", // selected "data-[state=active]:bg-white data-[state=active]:text-gray-900 data-[state=active]:shadow", "data-[state=active]:dark:bg-gray-950 data-[state=active]:dark:text-gray-50", // disabled "data-[disabled]:pointer-events-none data-[disabled]:text-gray-400 data-[disabled]:opacity-50 data-[disabled]:dark:text-gray-600", ) }} const TabsTrigger = React.forwardRef< React.ElementRef<typeof TabsPrimitives.Trigger>, React.ComponentPropsWithoutRef<typeof TabsPrimitives.Trigger>>(({ className, children, ...props }, forwardedRef) => { const variant = React.useContext(TabsListVariantContext) return ( <TabsPrimitives.Trigger ref={forwardedRef} className={cx(getVariantStyles(variant), focusRing, className)} {...props} > {children} </TabsPrimitives.Trigger> )}) TabsTrigger.displayName = "TabsTrigger" const TabsContent = React.forwardRef< React.ElementRef<typeof TabsPrimitives.Content>, React.ComponentPropsWithoutRef<typeof TabsPrimitives.Content>>(({ className, ...props }, forwardedRef) => ( <TabsPrimitives.Content ref={forwardedRef} className={cx("outline-none", focusRing, className)} {...props} />)) TabsContent.displayName = "TabsContent" export { Tabs, TabsContent, TabsList, TabsTrigger }
Example: Tabs solid variant
You have 60 days from the time we've shipped your order to return any part of it to us for a refund, provided it is still in its original, unused condition: we do not accept returns of used items.
No return authorization (RMA) is required. If you are within the United States, a pre-paid shipping label will be generated. For direct returns, a flat fee of $10 is deducted from your return for shipping and processing costs.
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/Tabs"
export const TabsExample = () => ( <Tabs defaultValue="tab1"> <TabsList variant="solid"> <TabsTrigger value="tab1">Returns</TabsTrigger> <TabsTrigger value="tab2">Shipping</TabsTrigger> </TabsList> <div className="ml-2 mt-4"> <TabsContent value="tab1" className="space-y-2 text-sm leading-7 text-gray-600 dark:text-gray-500" > <p> You have 60 days from the time we've shipped your order to return any part of it to us for a refund, provided it is still in its original, unused condition: we do not accept returns of used items. </p> <p> No return authorization (RMA) is required. If you are within the United States, a pre-paid shipping label will be generated. For direct returns, a flat fee of $10 is deducted from your return for shipping and processing costs. </p> </TabsContent> <TabsContent value="tab2" className="space-y-2 text-sm leading-7 text-gray-600 dark:text-gray-500" > <p> We ship worldwide via UPS Expedited. We offer flat rate shipping to customers in Canada ($30), the EU, Japan, and Singapore ($45–$65+), and Australia ($65). Note that most brokerage fees are included in the price of UPS Expedited shipping, with the exception of a possible $10 fee assessed in Canada only if prior arrangements to pay for duties and taxes are not made (see next question and answer). </p> <p> Outside of the United States, tariffs, duties, and taxes are the responsibility of the customer and are usually paid at time of delivery. </p> </TabsContent> </div> </Tabs>);
Example: Tabs with disabled trigger
Tab 1 content
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/Tabs"
export const TabsDisabledExample = () => ( <Tabs defaultValue="tab1"> <TabsList variant="line"> <TabsTrigger value="tab1">Tab 1</TabsTrigger> <TabsTrigger value="tab2">Tab 2</TabsTrigger> <TabsTrigger value="tab3" disabled> Tab 3 </TabsTrigger> </TabsList> <div className="mt-4"> <TabsContent value="tab1"> <p className="text-sm text-gray-500 sm:text-gray-500">Tab 1 content</p> </TabsContent> <TabsContent value="tab2"> <p className="text-sm text-gray-500 sm:text-gray-500">Tab 2 content</p> </TabsContent> <TabsContent value="tab3"> <p className="text-sm text-gray-500 sm:text-gray-500">Tab 3 content</p> </TabsContent> </div> </Tabs>);
Example: Tabs with icons
Tab 1 content
Tab 1 content
import { RiCalculatorLine, RiMapPin2Line } from "@remixicon/react"import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/Tabs"import { Tabs, TabsContent, TabsList, TabsTrigger,} from "@/components/Tabs"
export const TabsWithIconsExample = () => ( <div className="flex flex-col gap-12"> <Tabs defaultValue="tab1"> <TabsList variant="line"> <TabsTrigger value="tab1" className="inline-flex gap-2"> <RiMapPin2Line className="-ml-1 size-4" aria-hidden="true" /> Pic location </TabsTrigger> <TabsTrigger value="tab2" className="inline-flex gap-2"> <RiCalculatorLine className="-ml-1 size-4" aria-hidden="true" /> Calculate location </TabsTrigger> </TabsList> <div className="mt-4"> <TabsContent value="tab1"> <p className="text-sm text-gray-500 sm:text-gray-500"> Tab 1 content </p> </TabsContent> <TabsContent value="tab2"> <p className="text-sm text-gray-500 sm:text-gray-500"> Tab 2 content </p> </TabsContent> </div> </Tabs> <Tabs defaultValue="tab1"> <TabsList variant="solid"> <TabsTrigger value="tab1" className="gap-1.5"> <RiMapPin2Line className="-ml-1 size-4" aria-hidden="true" /> Pic location </TabsTrigger> <TabsTrigger value="tab2" className="gap-1.5"> <RiCalculatorLine className="-ml-1 size-4" aria-hidden="true" /> Calculate location </TabsTrigger> </TabsList> <div className="mt-4"> <TabsContent value="tab1"> <p className="text-sm text-gray-500 sm:text-gray-500"> Tab 1 content </p> </TabsContent> <TabsContent value="tab2"> <p className="text-sm text-gray-500 sm:text-gray-500"> Tab 2 content </p> </TabsContent> </div> </Tabs> </div>);
Example: Streched tabs
Tab 1 content
Tab 1 content
import { Tabs, TabsContent, TabsList, TabsTrigger,} from "@/components/Tabs"
export const TabsStretchWidthExample = () => ( <div className="flex flex-col gap-6"> <Tabs defaultValue="tab1"> <TabsList className="grid w-full grid-cols-3" variant="line"> <TabsTrigger value="tab1">Tab 1</TabsTrigger> <TabsTrigger value="tab2">Tab 2</TabsTrigger> <TabsTrigger value="tab3">Tab 3</TabsTrigger> </TabsList> <div className="mt-4"> <TabsContent value="tab1"> <p className="text-sm text-gray-500 sm:text-gray-500"> Tab 1 content </p> </TabsContent> <TabsContent value="tab2"> <p className="text-sm text-gray-500 sm:text-gray-500"> Tab 2 content </p> </TabsContent> <TabsContent value="tab3"> <p className="text-sm text-gray-500 sm:text-gray-500"> Tab 3 content </p> </TabsContent> </div> </Tabs> <Tabs defaultValue="tab1"> <TabsList className="grid w-full grid-cols-3" variant="solid"> <TabsTrigger value="tab1">Tab 1</TabsTrigger> <TabsTrigger value="tab2">Tab 2</TabsTrigger> <TabsTrigger value="tab3">Tab 3</TabsTrigger> </TabsList> <div className="mt-4"> <TabsContent value="tab1"> <p className="text-sm text-gray-500 sm:text-gray-500"> Tab 1 content </p> </TabsContent> <TabsContent value="tab2"> <p className="text-sm text-gray-500 sm:text-gray-500"> Tab 2 content </p> </TabsContent> <TabsContent value="tab3"> <p className="text-sm text-gray-500 sm:text-gray-500"> Tab 3 content </p> </TabsContent> </div> </Tabs> </div>);
API Reference: Tabs
This component uses the Radix UI API.
Note: The orientation prop has been removed.
API Reference: TabsList
This component uses the Radix UI API.
- variant
- Set a predefined look.
Default: "line"
API Reference: TabsTrigger
This component uses the Radix UI API.
API Reference: TabsContent
This component uses the Radix UI API.