Tabs
A set of layered sections of content known as tab panels that are displayed one at a time.
Account Settings
Make changes to your account here. Click save when you're done.
"use client";
import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs/tabs";
import { Button } from "@/components/ui/button/button";
import styles from "./tabs-demo.module.css";
const tabs = [
{ id: "account", label: "Account" },
{ id: "password", label: "Password" },
{ id: "team", label: "Team" },
];
export default function TabsBasic() {
return (
<div className={styles.container}>
<Tabs defaultValue="account">
<TabsList>
{tabs.map((tab) => (
<TabsTrigger key={tab.id} value={tab.id}>
{tab.label}
</TabsTrigger>
))}
</TabsList>
<TabsContent value="account">
<div className={styles.tabContent}>
<div>
<h3 className={styles.heading}>
Account Settings
</h3>
<p className={styles.description}>
Make changes to your account here. Click save when you're done.
</p>
</div>
<div className={styles.buttonGroup}>
<Button size="sm">Save Changes</Button>
<Button variant="outline" size="sm">
Cancel
</Button>
</div>
</div>
</TabsContent>
<TabsContent value="password">
<div className={styles.tabContent}>
<div>
<h3 className={styles.heading}>
Password
</h3>
<p className={styles.description}>
Change your password here. After saving, you'll be logged out.
</p>
</div>
<div className={styles.buttonGroup}>
<Button size="sm">Update Password</Button>
<Button variant="outline" size="sm">
Cancel
</Button>
</div>
</div>
</TabsContent>
<TabsContent value="team">
<div className={styles.tabContent}>
<div>
<h3 className={styles.heading}>
Team Management
</h3>
<p className={styles.description}>
Invite and manage your team members here.
</p>
</div>
<div className={styles.buttonGroup}>
<Button size="sm">Invite Member</Button>
<Button variant="outline" size="sm">
Manage Roles
</Button>
</div>
</div>
</TabsContent>
</Tabs>
</div>
);
}
Installation
npx shadcn@latest add https://roiui.com/r/tabs.json
Anatomy
anatomy
import {
Tabs,
TabsList,
TabsTrigger,
TabsContent,
} from '../ui/tabs'
<Tabs>
<TabsList>
<TabsTrigger />
</TabsList>
<TabsContent />
</Tabs>
Examples
With Motion
Account Settings
Make changes to your account here. Click save when you're done.
Password
Change your password here. After saving, you'll be logged out.
Team Management
Invite and manage your team members here.
Billing
View your billing information and payment methods.
"use client";
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs/tabs";
import { Button } from "@/components/ui/button/button";
import { motion } from "motion/react";
import { useState, useRef, useEffect } from "react";
import styles from "./tabs-motion.module.css";
const tabs = [
{ id: "account", label: "Account" },
{ id: "password", label: "Password" },
{ id: "team", label: "Team" },
{ id: "billing", label: "Billing" },
];
const bubbleVariants = {
animate: (bubbleStyle: { left: number; width: number }) => ({
left: bubbleStyle.left,
width: bubbleStyle.width,
}),
};
const bubbleTransition = {
type: "spring" as const,
bounce: 0.2,
duration: 0.6,
};
const contentVariants = {
active: { x: 0, opacity: 1, filter: "blur(0px)" },
inactive: (direction: number) => ({
x: direction > 0 ? 100 : -100,
opacity: 0,
filter: "blur(4px)",
}),
};
const contentTransition = {
type: "spring" as const,
bounce: 0.1,
duration: 0.5,
opacity: { duration: 0.3 },
filter: { duration: 0.3 },
};
export default function TabsFramerMotion() {
const [activeTab, setActiveTab] = useState("account");
const [bubbleStyle, setBubbleStyle] = useState({ left: 0, width: 0 });
const tabRefs = useRef<(HTMLElement | null)[]>([]);
useEffect(() => {
const activeIndex = tabs.findIndex((tab) => tab.id === activeTab);
const activeTabElement = tabRefs.current[activeIndex];
if (activeTabElement) {
const { offsetLeft, offsetWidth } = activeTabElement;
setBubbleStyle({ left: offsetLeft, width: offsetWidth });
}
}, [activeTab]);
return (
<div className={styles.container}>
<Tabs value={activeTab} onValueChange={setActiveTab}>
<TabsList className={styles.tabsList}>
{tabs.map((tab, index) => (
<TabsTrigger
key={tab.id}
value={tab.id}
data-framer-motion="true"
ref={(el) => {
tabRefs.current[index] = el as HTMLElement;
}}
className={styles.tabTrigger}
>
<span className={styles.tabLabel}>{tab.label}</span>
</TabsTrigger>
))}
<motion.span
className={styles.bubble}
variants={bubbleVariants}
animate="animate"
custom={bubbleStyle}
transition={bubbleTransition}
/>
</TabsList>
<div className={styles.contentContainer}>
{tabs.map((tab, index) => {
const isActive = activeTab === tab.id;
const currentIndex = tabs.findIndex((t) => t.id === activeTab);
return (
<motion.div
key={tab.id}
initial={false}
variants={contentVariants}
animate={isActive ? "active" : "inactive"}
custom={index > currentIndex ? 1 : -1}
transition={contentTransition}
className={styles.tabContent}
style={{ pointerEvents: isActive ? "auto" : "none" }}
>
{tab.id === "account" && (
<>
<div>
<h3 className={styles.heading}>
Account Settings
</h3>
<p className={styles.description}>
Make changes to your account here. Click save when you're done.
</p>
</div>
<div className={styles.buttonGroup}>
<Button size="sm">Save Changes</Button>
<Button variant="outline" size="sm">
Cancel
</Button>
</div>
</>
)}
{tab.id === "password" && (
<>
<div>
<h3 className={styles.heading}>
Password
</h3>
<p className={styles.description}>
Change your password here. After saving, you'll be logged out.
</p>
</div>
<div className={styles.buttonGroup}>
<Button size="sm">Update Password</Button>
<Button variant="outline" size="sm">
Cancel
</Button>
</div>
</>
)}
{tab.id === "team" && (
<>
<div>
<h3 className={styles.heading}>
Team Management
</h3>
<p className={styles.description}>
Invite and manage your team members here.
</p>
</div>
<div className={styles.buttonGroup}>
<Button size="sm">Invite Member</Button>
<Button variant="outline" size="sm">
Manage Roles
</Button>
</div>
</>
)}
{tab.id === "billing" && (
<>
<div>
<h3 className={styles.heading}>
Billing
</h3>
<p className={styles.description}>
View your billing information and payment methods.
</p>
</div>
<div className={styles.buttonGroup}>
<Button size="sm">Save Changes</Button>
<Button variant="outline" size="sm">
Cancel
</Button>
</div>
</>
)}
</motion.div>
);
})}
</div>
</Tabs>
</div>
);
}