Animated Tabs
Image tabs (or FAQs) where users navigate through images using tabs
Image tabs (or FAQs) where users navigate through images using tabs
UI components can improve UX by providing familiar, consistent interactions that make it easy for users to navigate and interact with an application.
npm install framer-motion
1<TabsProvider defaultValue='01' className='md:grid md:grid-cols-12'>2<TabList className='md:col-span-5'>3<TabItem value={'01'}>4<TabHeader value={'01'}>title01</TabHeader>5<TabDes value={'01'}>description</TabDes>6</TabItem>7<TabItem value={'02'}>8<TabHeader value={'02'}>title02</TabHeader>9<TabDes value={'02'}>description</TabDes>10</TabItem>11<TabItem value={'03'}>12<TabHeader value={'03'}>title03</TabHeader>13<TabDes value={'03'}>description</TabDes>14</TabItem>15</TabList>16<TabImageContainer className='md:col-span-7'>17<TabImage value={'01'}>18<img src={''} alt={''} />19</TabImage>20<TabImage value={'02'}>21<img src={''} alt={''} />22</TabImage>23<TabImage value={'03'}>24<img src={''} alt={''} />25</TabImage>26</TabImageContainer>27</TabsProvider>
1'use client';2import React, { ReactNode, useState, createContext, useContext } from 'react';3import { AnimatePresence, motion } from 'framer-motion';4import { cn } from '@/lib/utils';5import { useMediaQuery } from '@/hooks/use-media-query';67interface Tab {8id: string;9title: string;10description: string;11imageUrl: string;12}1314interface TabsContextType {15activeTab: string;16setActiveTab: (id: string) => void;17isDesktop: boolean;18}1920const TabsContext = createContext<TabsContextType | undefined>(undefined);2122const useTabs = () => {23const context = useContext(TabsContext);24if (!context) {25throw new Error('Tabs components must be used within a TabsProvider');26}27return context;28};2930export function TabsProvider({31children,32defaultValue,33className,34}: {35children: ReactNode;36defaultValue: string;37className?: string;38}) {39const [activeTab, setActiveTab] = useState(defaultValue);40const isDesktop = useMediaQuery('(min-width: 768px)');41return (42<TabsContext.Provider value={{ activeTab, setActiveTab, isDesktop }}>43<div className={cn('w-full h-full', className)}>{children}</div>44</TabsContext.Provider>45);46}4748export function TabList({49children,50className,51}: {52children: ReactNode;53className?: string;54}) {55return <div className={cn('rounded-sm h-fit', className)}>{children}</div>;56}5758export function TabItem({59children,60value,61index,62}: {63children: ReactNode;64value: string;65index: number;66}) {67const { activeTab, setActiveTab } = useTabs();6869return (70<motion.div71className={`rounded-lg overflow-hidden mb-2 ${72activeTab === value73? 'active border-2 dark:border-[#656fe2] border-[#F2F2F2] dark:bg-[#E0ECFB] bg-[#F2F2F2]'74: 'bg-transparent border-2 dark:hover:border-[#656fe2]'75}`}76onClick={() => setActiveTab(value)}77>78{children}79</motion.div>80);81}8283export function TabHeader({84children,85value,86}: {87children: ReactNode;88value: string;89}) {90const { activeTab } = useTabs();91return (92<h393className={`p-4 cursor-pointer transition-all font-semibold dark:text-white text-black dark:hover:bg-[#1e2a78] hover:bg-[#F2F2F2] dark:hover:text-white hover:text-black flex justify-between items-center ${94activeTab === value95? 'active dark:bg-[#1e2a78] bg-[#F2F2F2]'96: 'dark:bg-[#11112b] bg-white'97}`}98>99{children}100</h3>101);102}103104export function TabDes({105children,106value,107}: {108children: ReactNode;109value: string;110}) {111const { activeTab } = useTabs();112return (113<AnimatePresence mode='sync'>114{activeTab === value && (115<motion.div116initial={{ height: 0, opacity: 0 }}117animate={{ height: 'auto', opacity: 1 }}118exit={{ height: 0, opacity: 0 }}119transition={{120duration: 0.3,121ease: 'easeInOut',122delay: 0.14,123}}124>125<p className={`dark:bg-white bg-[#F2F2F2] text-black p-3`}>126{children}127</p>128</motion.div>129)}130</AnimatePresence>131);132}133134export function TabImageContainer({135children,136className,137}: {138children: ReactNode;139className?: string;140}) {141return (142<div className={cn('', className)}>143<AnimatePresence mode='popLayout'>{children}</AnimatePresence>144</div>145);146}147148export function TabImage({149children,150value,151index,152}: {153children: ReactNode;154value: string;155index: number;156}) {157const { activeTab, isDesktop } = useTabs();158159if (activeTab !== value || !isDesktop) return null;160161return (162<motion.div className='p-4 h-[400px] overflow-hidden'>163<motion.div164initial={{ opacity: 0, overflow: 'hidden' }}165animate={{ opacity: 1, overflow: 'hidden' }}166exit={{ opacity: 0, overflow: 'hidden' }}167transition={{168duration: 0.4,169delay: 0.2,170}}171>172{children}173</motion.div>174</motion.div>175);176}
UI components can improve UX by providing familiar, consistent interactions that make it easy for users to navigate and interact with an application.
UI components can improve UX by providing familiar, consistent interactions that make it easy for users to navigate and interact with an application.