Staggered Flipping Link
A fun animated link or element that flips the letters up on hover
Installation
1
Install dependencies
npm install framer-motion tailwind-merge clsx
2
Add util file
lib/utils.ts
import { ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
3
Copy the source code
components/ui/staggered-hover.tsx
'use client';
import { motion } from 'framer-motion';
import React, { Children, isValidElement, ReactNode, cloneElement } from 'react';
interface StaggeredFlipProps {
children: ReactNode;
href?: string;
duration?: number;
stagger?: number;
}
export function StaggeredFlip ({
children,
href,
duration = 0.2,
stagger = 0.03,
}: StaggeredFlipProps) {
const childrenArray = Children.toArray(children).map((child, index) => {
if (typeof child === 'string') {
return child.split('').map((char, charIndex) => (
<span key={`${index}-${charIndex}`}>{char}</span>
));
}
if (isValidElement(child)) {
return cloneElement(child, { key: index });
}
return child;
}).flat();
const WrapperComponent = href ? motion.a : motion.div;
const wrapperProps = href ? { href } : {};
return (
<WrapperComponent
initial="initial"
whileHover="hovered"
{...wrapperProps}
className={`relative block overflow-hidden whitespace-nowrap text-4xl font-black uppercase sm:text-7xl md:text-8xl lg:text-9xl`}
style={{
lineHeight: 0.75,
}}
>
<div>
{childrenArray.map((child, i) => (
<motion.span
variants={{
initial: {
y: 0,
},
hovered: {
y: "-100%",
},
}}
transition={{
duration,
ease: "easeInOut",
delay: stagger * i,
}}
className="inline-block"
key={`top-${i}`}
>
{child}
</motion.span>
))}
</div>
<div className="absolute inset-0">
{childrenArray.map((child, i) => (
<motion.span
variants={{
initial: {
y: "100%",
},
hovered: {
y: 0,
},
}}
transition={{
duration,
ease: "easeInOut",
delay: stagger * i,
}}
className="inline-block"
key={`bottom-${i}`}
>
{child}
</motion.span>
))}
</div>
</WrapperComponent>
);
};
Props
Prop | Type | Description | Default Value |
---|---|---|---|
children | ReactNode | The content to be animated - can be string or React nodes | undefined |
href | string | The URL that the component links to | undefined |
duration | number | Duration of the flip animation in seconds | 0.2 |
stagger | number | Delay between each character's animation in seconds | 0.03 |