Components
Text Reveal
Text Reveal
A stylish effect that sequentially fades in text on page load, creating a dynamic reveal.
ForgeUIisabeautifullydesignedcomponentlibrarybuiltwithTailwindCSSandMotion.Ithelpsdevelopersbuildmodern,animatedUIsfaster,withconsistentstylingandproduction-readycomponents.
Installation
1
Install the packages
npm i motion clsx tailwind-merge
2
Add util file
lib/util.ts
import { ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
import { ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
3
Copy and paste the following code into your project
text-reveal.tsx
"use client";
import { useEffect } from "react";
import { motion, stagger, useAnimate } from "motion/react";
import { cn } from "@/lib/utils";
const TextReveal = ({
text,
className,
filter = true,
duration = 0.5,
staggerDelay = 0.2,
}: {
text: string;
className?: string;
filter?: boolean;
duration?: number;
staggerDelay?: number;
}) => {
const [scope, animate] = useAnimate();
const textArray = text.split(" ");
useEffect(() => {
animate(
"span",
{
opacity: 1,
filter: filter ? "blur(0px)" : "none",
},
{
duration: duration,
delay: stagger(staggerDelay),
ease: "easeOut",
},
);
}, [animate, duration, filter, staggerDelay]);
return (
<div className={cn("leading-[1.5]", className)}>
<motion.div ref={scope}>
{textArray.map((word, idx) => {
return (
<motion.span
key={word + idx}
className="inline-block"
style={{
filter: filter ? "blur(8px)" : "none",
marginRight: "0.25rem",
opacity: 0,
}}
>
{word}
</motion.span>
);
})}
</motion.div>
</div>
);
};
export default TextReveal;
"use client";
import { useEffect } from "react";
import { motion, stagger, useAnimate } from "motion/react";
import { cn } from "@/lib/utils";
const TextReveal = ({
text,
className,
filter = true,
duration = 0.5,
staggerDelay = 0.2,
}: {
text: string;
className?: string;
filter?: boolean;
duration?: number;
staggerDelay?: number;
}) => {
const [scope, animate] = useAnimate();
const textArray = text.split(" ");
useEffect(() => {
animate(
"span",
{
opacity: 1,
filter: filter ? "blur(0px)" : "none",
},
{
duration: duration,
delay: stagger(staggerDelay),
ease: "easeOut",
},
);
}, [animate, duration, filter, staggerDelay]);
return (
<div className={cn("leading-[1.5]", className)}>
<motion.div ref={scope}>
{textArray.map((word, idx) => {
return (
<motion.span
key={word + idx}
className="inline-block"
style={{
filter: filter ? "blur(8px)" : "none",
marginRight: "0.25rem",
opacity: 0,
}}
>
{word}
</motion.span>
);
})}
</motion.div>
</div>
);
};
export default TextReveal;
4
Update the import paths to match your project setup
Props
Prop | Type | Default | Description |
---|---|---|---|
text | string | - | The text content to reveal with the animation. |
className | string | - | Optional Tailwind CSS classes to style the wrapper element. |
filter | boolean | true | Applies a blur effect that transitions during the reveal animation. |
duration | number | 0.5 | Animation duration (in seconds) for each word. |
staggerDelay | number | 0.2 | Delay between each word's animation start time. |