Animated Background
An animated background effect that highlights elements smoothly on hover or click, enhancing user interaction.
Bugatti Chiron
Quad-turbo W16, pure speed. A masterpiece of engineering designed for breathtaking acceleration and top speeds.
Lamborghini Revuelto
Hybrid V12 with insane power. Combines electrification with legendary Italian performance for unmatched thrill.
Ferrari SF90
Plug-in hybrid with 1000 HP. A blend of electrification and raw horsepower delivering unparalleled driving dynamics.
McLaren P1
F1 tech in a road car. A hybrid hypercar that merges Formula 1 innovations with everyday drivability and power.
Porsche 918 Spyder
Hybrid hypercar, ultimate grip. A fusion of cutting-edge technology and extreme handling precision on any road.
Koenigsegg Jesko
Revs up to 8500 RPM. Designed for extreme speed, aerodynamics, and record-breaking track performance.
Installation
- 1
Install Dependencies
npm i motion
- 2
lib/utils.ts
import { clsx, type ClassValue } from "clsx" import { twMerge } from "tailwind-merge" export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)) }
- 3
Copy the source code
@/components/ui/animated-background.tsx
'use client'; import { cn } from '@/lib/utils'; import { AnimatePresence, Transition, motion } from 'motion/react'; import { Children, cloneElement, ReactElement, useEffect, useState, useId, } from 'react'; export type AnimatedBackgroundProps = { children: | ReactElement<{ 'data-id': string }>[] | ReactElement<{ 'data-id': string }>; defaultValue?: string; onValueChange?: (newActiveId: string | null) => void; className?: string; transition?: Transition; enableHover?: boolean; }; export default function AnimatedBackground({ children, defaultValue, onValueChange, className, transition, enableHover = false, }: AnimatedBackgroundProps) { const [activeId, setActiveId] = useState<string | null>(null); const uniqueId = useId(); const handleSetActiveId = (id: string | null) => { setActiveId(id); if (onValueChange) { onValueChange(id); } }; useEffect(() => { if (defaultValue !== undefined) { setActiveId(defaultValue); } }, [defaultValue]); return Children.map(children, (child: any, index) => { const id = child.props['data-id']; const interactionProps = enableHover ? { onMouseEnter: () => handleSetActiveId(id), onMouseLeave: () => handleSetActiveId(null), } : { onClick: () => handleSetActiveId(id), }; return cloneElement( child, { key: index, className: cn('relative inline-flex', child.props.className), 'data-checked': activeId === id ? 'true' : 'false', ...interactionProps, }, <> <AnimatePresence initial={false}> {activeId === id && ( <motion.div layoutId={`background-${uniqueId}`} className={cn('absolute inset-0', className)} transition={transition} initial={{ opacity: defaultValue ? 1 : 0 }} animate={{ opacity: 1, }} exit={{ opacity: 0, }} /> )} </AnimatePresence> <div className='z-10'>{child.props.children}</div> </> ); }); }
AnimatedBackgroundProps
Prop | Type | Default | Description |
---|---|---|---|
className | string | undefined | Additional custom class names for styling the animated background. |
children | ReactElement<{ 'data-id': string }>[] | ReactElement<{ 'data-id': string }> | - | An array or a single React element with a `data-id` attribute used for tracking active elements. |
defaultValue | string | undefined | Specifies which item should be highlighted by default. |
onValueChange | (newActiveId: string | null) => void | undefined | Callback function triggered when the active element changes. |
transition | Transition | undefined | Defines the transition animation properties using the Motion library. |
enableHover | boolean | false | Enables hover-based activation instead of click-based interaction. |