Forgeui
uianimated-tabssource: ok · hit
Animated Tabs
Switch tabs smoothly with motion-based underline or highlight effects.
npx shadcn add "https://forgeui.in/r/animated-tabs.json"free
No selection tags yet — empty means no evidence, not lack of support.
Files1 · source cached 10/8/2026, 10:25:04 PM
registry/components/animatedtabs/animatedtabs.tsx
"use client";
import { useState } from "react";
import { motion } from "motion/react";
import { cn } from "@/lib/utils";
type AnimatedTabsProps = {
tabs?: Array<string>;
variant?: "default" | "underline";
};
const defaultTabs = ["Home", "Components", "Docs", "Templates"];
const AnimatedTabs = ({
tabs = defaultTabs,
variant = "default",
}: AnimatedTabsProps) => {
const [activeTab, setActiveTab] = useState(tabs[0]);
if (variant === "underline") {
return (
<div className="border-border relative flex items-center border-b">
{tabs.map((tab, index) => {
const isActive = activeTab === tab;
return (
<button
key={index}
type="button"
onClick={() => setActiveTab(tab)}
className={cn(
"relative flex h-10 items-center px-4 text-sm font-medium transition-colors duration-200",
isActive
? "text-primary"
: "text-muted-foreground hover:text-foreground",
)}
>
{isActive && (
<motion.div
layoutId="active-tab-underline"
className="bg-primary absolute right-0 bottom-0 left-0 h-0.5"
initial={false}
transition={{
type: "spring",
stiffness: 500,
damping: 30,
}}
/>
)}
<span className="relative z-10">{tab}</span>
</button>
);
})}
</div>
);
}
return (
<div className="relative mx-auto flex w-fit items-center rounded-full border border-neutral-200/60 bg-neutral-50 p-1 dark:border-neutral-800/70 dark:bg-neutral-900/70">
{tabs.map((tab, index) => {
const isActive = activeTab === tab;
return (
<button
key={index}
type="button"
onClick={() => setActiveTab(tab)}
className={cn(
"relative flex h-8 items-center rounded-full px-3 text-sm font-medium transition-colors duration-200",
isActive
? "text-primary-foreground"
: "text-muted-foreground hover:text-foreground",
)}
>
{isActive && (
<motion.div
layoutId="active-tab-background"
className="bg-primary absolute inset-0 rounded-full"
initial={false}
transition={{
type: "spring",
stiffness: 500,
damping: 30,
}}
/>
)}
<span className="relative z-10">{tab}</span>
</button>
);
})}
</div>
);
};
export default AnimatedTabs;