Installation
Copy and paste the following code into your project.
components/ui/motion-text.tsx
import React from "react";
import { motion } from "framer-motion";
import { cn } from "@/lib/utils";
interface MotionTextProps {
text: string;
className?: string;
effect?: "fade" | "slide" | "glitch";
duration?: number;
delay?: number;
stagger?: number;
color?: string;
fontSize?: string | number;
}
type VariantType = {
initial: any;
animate: any;
transition?: {
duration?: number;
repeat?: number;
repeatDelay?: number;
delay?: number;
ease?: string;
};
};
const effectVariants: Record<string, (index: number) => VariantType> = {
fade: (index: number) => ({
initial: { opacity: 0, y: 20 },
animate: { opacity: 1, y: 0 },
transition: {
duration: 0.3,
delay: index * 0.1,
},
}),
slide: (index: number) => ({
initial: { x: -20, opacity: 0 },
animate: { x: 0, opacity: 1 },
transition: {
duration: 0.3,
delay: index * 0.08,
},
}),
glitch: (index: number) => ({
initial: { x: 0 },
animate: {
x: [0, -3, 3, -3, 3, 0],
y: [0, 2, -2, 2, -2, 0],
filter: [
"none",
"brightness(150%) contrast(150%)",
"none",
"brightness(150%) contrast(150%)",
"none",
],
},
transition: {
duration: 0.3,
repeat: Infinity,
repeatDelay: 4,
delay: index * 0.05,
},
}),
};
export function MotionText({
text,
className,
effect = "fade",
duration = 0.3,
delay = 0,
stagger = 0.05,
color,
fontSize,
}: MotionTextProps) {
const characters = text.split("");
return (
<span className={cn("inline-block", className)} style={{ color, fontSize }}>
{characters.map((char, index) => {
const variant = effectVariants[effect](index);
return (
<motion.span
key={index}
initial={variant.initial}
animate={variant.animate}
transition={variant.transition}
className="relative inline-block"
style={{
willChange: "transform",
backfaceVisibility: "hidden",
}}
>
{char === " " ? "\u00A0" : char}
</motion.span>
);
})}
</span>
);
}
Update the import paths to match your project setup.
import MotionText from "@/components/ui/motion-text";
Usage
import MotionText from "@/components/ui/motion-text";
export default function Example() {
return (
<div className="space-y-8">
{/* Fade Effect */}
<MotionText
text="Character by Character Fade In"
effect="fade"
stagger={0.1}
/>
{/* Glitch Effect */}
<MotionText
text="Individual Character Glitch Effect"
effect="glitch"
stagger={0.02}
/>
{/* Slide Effect */}
<MotionText
text="Characters Sliding One By One"
effect="slide"
stagger={0.08}
/>
</div>
);
}
Props
Name | Type | Default | Description |
---|---|---|---|
text | string | The text content to animate. | |
effect | `"fade" | "fade" | The animation effect to apply to each character. |
duration | number | 0.3 | Duration of the animation in seconds. |
delay | number | 0 | Initial delay before starting the animation. |
stagger | number | 0.05 | Delay between each character's animation. |
color | string | Text color. Accepts any valid CSS color value. | |
fontSize | string | Font size. Accepts any valid CSS font-size value. | |
className | string | Additional CSS classes to apply to the text container. |
Examples
Fade Effect
The fade effect smoothly transitions each character from invisible to visible with a subtle upward movement.
<MotionText text="Character by Character Fade In" effect="fade" stagger={0.1} />
Glitch Effect
The glitch effect creates a cyberpunk-style animation with rapid position shifts and contrast changes.
<MotionText
text="Individual Character Glitch Effect"
effect="glitch"
stagger={0.02}
/>
Slide Effect
The slide effect makes characters appear by sliding them in from the left.
<MotionText
text="Characters Sliding One By One"
effect="slide"
stagger={0.08}
/>
Customization
You can customize the appearance of the text using standard CSS classes or inline styles:
<MotionText
text="Custom Styled Text"
effect="fade"
className="font-bold text-5xl bg-linear-to-r from-purple-500 to-pink-500 text-transparent bg-clip-text"
stagger={0.1}
/>
Each animation effect can be fine-tuned using the duration
and stagger
props to achieve the desired timing and flow.