Animated Tabs
scrollxui/animated-tabsFreeComponent
A headless and styled tab UI component set for switching content views.
Live preview
live · rendered by the registry
Rendered by scrollxui on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://scrollxui.dev/registry/animated-tabs.jsonSource
1"use client";23import React, {4 createContext,5 useContext,6 useState,7 ReactNode,8 ReactElement,9} from "react";10import { twMerge } from "tailwind-merge";1112interface TabsContextProps {13 activeTab: string;14 setActiveTab: (value: string) => void;15}1617const TabsContext = createContext<TabsContextProps | undefined>(undefined);1819function useTabsContext() {20 const context = useContext(TabsContext);21 if (!context) {22 throw new Error("Tabs components must be used within <Tabs>");23 }24 return context;25}2627interface TabsProps {28 defaultValue: string;29 children: ReactNode;30}3132const Tabs = ({ defaultValue, children }: TabsProps) => {33 const [activeTab, setActiveTab] = useState(defaultValue);3435 return (36 <TabsContext.Provider value={{ activeTab, setActiveTab }}>37 <div className="w-full">{children}</div>38 </TabsContext.Provider>39 );40};4142const TabsList = ({ children }: { children: ReactNode }) => {43 return (44 <div className="flex border-b border-gray-200 dark:border-gray-800">45 {children}46 </div>47 );48};4950interface TabsTriggerProps {51 value: string;52 children: ReactNode;53}5455const TabsTrigger = ({ value, children }: TabsTriggerProps) => {56 const { activeTab, setActiveTab } = useTabsContext();57 const isActive = activeTab === value;5859 return (60 <button61 onClick={() => setActiveTab(value)}62 className="relative px-4 py-2 text-sm font-medium rounded-t-md overflow-hidden transition-colors duration-500"63 >64 <span65 className={twMerge(66 "relative z-10 capitalize transition-colors duration-300",67 isActive68 ? "text-white dark:text-black"69 : "text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100"70 )}71 >72 {children}73 </span>74 <span75 className={twMerge(76 "absolute bottom-0 left-0 h-full w-full origin-bottom scale-y-0 transition-transform duration-500 ease-out z-0 rounded-t-md",77 isActive ? "scale-y-100 bg-black dark:bg-white" : "bg-transparent"78 )}79 />80 </button>81 );82};8384interface TabsContentProps {85 value: string;86 children: ReactNode;87}8889const TabsContent = ({90 value,91 children,92}: TabsContentProps): ReactElement | null => {93 const { activeTab } = useTabsContext();94 return activeTab === value ? <div className="p-4">{children}</div> : null;95};9697export { Tabs, TabsList, TabsTrigger, TabsContent };
What it pulls in
npm packages
Files it writes
More from scrollxui
All 180 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Accordionaccordion | scrollxui | Components | Free | 4 deps | |
| Alert Dialogalert-dialog | scrollxui | Components | Free | 7 deps | |
| Animated Buttonanimated-button | scrollxui | Components | Free | 4 deps | |
| Animated Testimonialsanimated-testimonials | scrollxui | Components | Free | 2 deps | |
| Animated TextGenerateanimated-textgenerate | scrollxui | Components | Free | 3 deps | |
| Announcementannouncement | scrollxui | Components | Free | 5 deps | |
| Aspect Ratioaspect-ratio | scrollxui | Components | Free | 1 dep | |
| Aurora Dotsaurora-dots | scrollxui | Components | Free | 2 deps |
