Blur Text
Words fade up out of a blur, one after another.
Interfaces that move with intent and feel effortless.
components/ui/blur-text.tsx
"use client";
import { motion } from "motion/react";
type BlurTextProps = {
text: string;
className?: string;
/** Delay in seconds before the first word appears */
delay?: number;
/** Seconds between each word */
stagger?: number;
};
export function BlurText({ text, className = "", delay = 0, stagger = 0.06 }: BlurTextProps) {
const words = text.split(" ");
return (
<motion.p
className={className}
initial="hidden"
whileInView="visible"
viewport={{ once: true, amount: 0.4 }}
variants={{
hidden: {},
visible: { transition: { staggerChildren: stagger, delayChildren: delay } },
}}
>
{words.map((word, i) => (
<motion.span
key={`${word}-${i}`}
className="inline-block"
variants={{
hidden: { opacity: 0, filter: "blur(10px)", y: 14 },
visible: {
opacity: 1,
filter: "blur(0px)",
y: 0,
transition: { duration: 0.7, ease: [0.22, 1, 0.36, 1] },
},
}}
>
{word}
{i < words.length - 1 && " "}
</motion.span>
))}
</motion.p>
);
}
export default function Demo() {
return (
<BlurText
text="Interfaces that move with intent and feel effortless."
className="max-w-xl text-center text-4xl font-semibold tracking-tight text-zinc-900 sm:text-5xl"
/>
);
}
Installation
Install the dependencies
$ npm i motion lucide-reactCopy the source into
components/ui/blur-text.tsxcomponents/ui/blur-text.tsx"use client"; import { motion } from "motion/react"; type BlurTextProps = { text: string; className?: string; /** Delay in seconds before the first word appears */ delay?: number; /** Seconds between each word */ stagger?: number; }; export function BlurText({ text, className = "", delay = 0, stagger = 0.06 }: BlurTextProps) { const words = text.split(" "); return ( <motion.p className={className} initial="hidden" whileInView="visible" viewport={{ once: true, amount: 0.4 }} variants={{ hidden: {}, visible: { transition: { staggerChildren: stagger, delayChildren: delay } }, }} > {words.map((word, i) => ( <motion.span key={`${word}-${i}`} className="inline-block" variants={{ hidden: { opacity: 0, filter: "blur(10px)", y: 14 }, visible: { opacity: 1, filter: "blur(0px)", y: 0, transition: { duration: 0.7, ease: [0.22, 1, 0.36, 1] }, }, }} > {word} {i < words.length - 1 && " "} </motion.span> ))} </motion.p> ); } export default function Demo() { return ( <BlurText text="Interfaces that move with intent and feel effortless." className="max-w-xl text-center text-4xl font-semibold tracking-tight text-zinc-900 sm:text-5xl" /> ); }Use it
The file exports the component and a
Demoshowing typical usage. Import whichever you need.