Flip Reveal
Text enters with a 3D X-axis flip per character — rotateX 90→0 — staggered using framer-motion variants.
Use and inspectUse this when the motion supports the surrounding content. Connect callbacks and state to your app, keep the reset preview as a local demonstration, and add a reduced-motion fallback for movement or looping. The preview is synthetic; it does not call a backend.Next: inspect the source below and replace the demo inputs with your own data.
Flip RevealText enters with a 3D X-axis flip per character — rotateX 90→0 — staggered using framer-motion variants.
"use client";
import { useEffect, useState } from "react";
import { motion, type Variants } from "framer-motion";
type FlipRevealProps = {
text: string;
loop?: boolean;
duration?: number;
};
const containerVariants: Variants = {
hidden: {},
show: { transition: { staggerChildren: 0.06 } },
};
const charVariants: Variants = {
hidden: { opacity: 0, rotateX: 90 },
show: {
opacity: 1,
rotateX: 0,
transition: { duration: 0.4, ease: [0.22, 1, 0.36, 1] },
},
};
export function FlipReveal({ text, loop = false, duration = 2200 }: FlipRevealProps) {
const [key, setKey] = useState(0);
const chars = text.split("");
useEffect(() => {
if (!loop) return;
const id = setInterval(() => setKey((k) => k + 1), duration);
return () => clearInterval(id);
}, [loop, duration]);
return (
<motion.span
key={key}
className="mp-flip-reveal"
variants={containerVariants}
initial="hidden"
animate="show"
aria-label={text}
style={{ display: "inline-flex", perspective: "500px" }}
>
{chars.map((char, i) => (
<motion.span
key={i}
variants={charVariants}
className="mp-flip-reveal-char"
style={{
display: "inline-block",
transformOrigin: "50% 100%",
transformStyle: "preserve-3d",
}}
>
{char === " " ? "\u00A0" : char}
</motion.span>
))}
</motion.span>
);
}Install
npm install framer-motionProps
| Prop | Type | Default | Description |
|---|---|---|---|
| textrequired | string | — | Text to reveal with flip |
| loop | boolean | false | Restart the reveal on an interval |
| duration | number | 2200 | Loop interval in ms (when loop=true) |