Animated Tabs
Preview
This is the Home tab.
Code
"use client";
import { useState, type FC, type ReactNode } from "react";
import { motion, AnimatePresence } from "framer-motion";
import { cn } from "@/lib/utils";
interface Tab {
label: string;
content: ReactNode;
}
interface AnimatedTabsProps {
tabs: Tab[];
className?: string;
tabClassName?: string;
contentClassName?: string;
}
const AnimatedTabs: FC<AnimatedTabsProps> = ({
tabs,
className,
tabClassName,
contentClassName,
}) => {
const [activeTab, setActiveTab] = useState(0);
return (
<div className={cn("w-full max-w-md", className)}>
<div className="relative flex items-center justify-center border-b border-white/10">
{tabs.map((tab, index) => (
<button
key={tab.label}
onClick={() => setActiveTab(index)}
className={cn(
"relative z-10 px-4 py-2 text-sm font-medium transition-colors",
activeTab === index ? "text-white" : "text-gray-400 hover:text-white",
tabClassName
)}
>
{tab.label}
{activeTab === index && (
<motion.div
layoutId="active-tab-indicator"
className="absolute inset-x-0 bottom-[-1px] h-0.5 bg-purple-500"
transition={{ type: "spring", stiffness: 300, damping: 30 }}
/>
)}
</button>
))}
</div>
<div className={cn("relative mt-6 h-40", contentClassName)}>
<AnimatePresence mode="wait">
<motion.div
key={activeTab}
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -10 }}
transition={{ duration: 0.2 }}
className="w-full h-full flex items-center justify-center"
>
{typeof tabs[activeTab].content === 'string' ? (
<p className="text-center text-gray-300">{tabs[activeTab].content}</p>
) : (
tabs[activeTab].content
)}
</motion.div>
</AnimatePresence>
</div>
</div>
);
};
export default AnimatedTabs;