Tabs
ComponentsTabbed content switching.
Content for Tab 1
Live Functional Playground Interactive Hooks • useState
Overview Dashboard
Real-time metrics, active cloud nodes, and edge worker health telemetry.
Motion Physics & Animation Showcase Framer Motion ✨
Overview Panel
Watch the background pill glide with physical spring inertia when you switch tabs!
Format:
Required Animation Library: framer-motion & lucide-react
Install this package in your project before importing the animated component.
npm i framer-motion lucide-react <div class="w-full max-w-sm">
<div class="flex space-x-1 rounded-xl border border-border bg-muted p-1">
<button class="w-full rounded-lg bg-background py-1.5 text-sm font-medium text-foreground shadow">Tab 1</button>
<button class="w-full rounded-lg py-1.5 text-sm font-medium text-muted-foreground hover:bg-background/50">Tab 2</button>
</div>
<div class="mt-4 rounded-xl border border-border p-4 bg-card text-card-foreground">
Content for Tab 1
</div>
</div> <div className="w-full max-w-sm">
<div className="flex space-x-1 rounded-xl border border-border bg-muted p-1">
<button className="w-full rounded-lg bg-background py-1.5 text-sm font-medium text-foreground shadow">Tab 1</button>
<button className="w-full rounded-lg py-1.5 text-sm font-medium text-muted-foreground hover:bg-background/50">Tab 2</button>
</div>
<div className="mt-4 rounded-xl border border-border p-4 bg-card text-card-foreground">
Content for Tab 1
</div>
</div> "use client";
import React, { useState } from "react";
interface TabItem {
id: string;
label: string;
content: React.ReactNode;
}
const defaultTabs: TabItem[] = [
{ id: "account", label: "Account", content: "Make changes to your account settings and personal details here." },
{ id: "password", label: "Password", content: "Change your password here. After saving, you'll be prompted to sign back in." },
{ id: "notifications", label: "Notifications", content: "Customize how and when you receive automated project alerts." },
];
export default function Tabs({ tabs = defaultTabs }: { tabs?: TabItem[] }) {
const [activeTab, setActiveTab] = useState(tabs[0]?.id || "");
return (
<div className="w-full max-w-md">
<div className="flex space-x-1 rounded-xl border border-border bg-muted/60 p-1">
{tabs.map((tab) => {
const isActive = activeTab === tab.id;
return (
<button
key={tab.id}
type="button"
onClick={() => setActiveTab(tab.id)}
className={`w-full rounded-lg py-2 text-xs font-semibold transition-all cursor-pointer ${
isActive
? "bg-background text-foreground shadow-xs"
: "text-muted-foreground hover:text-foreground hover:bg-background/40"
}`}
>
{tab.label}
</button>
);
})}
</div>
<div className="mt-4 rounded-xl border border-border p-5 bg-card text-card-foreground text-xs leading-relaxed shadow-2xs">
{tabs.find((t) => t.id === activeTab)?.content}
</div>
</div>
);
} "use client";
import React, { useState } from "react";
import { motion } from "framer-motion";
const defaultTabs = [
{ id: "overview", label: "Overview", content: "Real-time analytics and system uptime performance overview." },
{ id: "integrations", label: "Integrations", content: "Manage connected third-party APIs, webhooks, and tokens." },
{ id: "settings", label: "Settings", content: "Adjust organization parameters, security, and member roles." },
];
export default function AnimatedTabs() {
const [activeTab, setActiveTab] = useState(defaultTabs[0].id);
return (
<div className="w-full max-w-md">
{/* Sliding pill tab navigation */}
<div className="relative flex space-x-1 rounded-xl border border-border/80 bg-muted/60 p-1.5">
{defaultTabs.map((tab) => {
const isActive = activeTab === tab.id;
return (
<button
key={tab.id}
type="button"
onClick={() => setActiveTab(tab.id)}
className={`relative w-full rounded-lg py-2 text-xs font-semibold transition-colors z-10 cursor-pointer ${
isActive ? "text-foreground" : "text-muted-foreground hover:text-foreground"
}`}
>
{isActive && (
<motion.div
layoutId="activeTabIndicator"
transition={{ type: "spring", stiffness: 450, damping: 30 }}
className="absolute inset-0 bg-background rounded-lg shadow-xs -z-10"
/>
)}
{tab.label}
</button>
);
})}
</div>
{/* Tab Content with fade & rise animation */}
<motion.div
key={activeTab}
initial={{ opacity: 0, y: 8 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.2 }}
className="mt-4 rounded-xl border border-border p-5 bg-card text-card-foreground text-xs leading-relaxed shadow-2xs"
>
{defaultTabs.find((t) => t.id === activeTab)?.content}
</motion.div>
</div>
);
}