Animated Text
A versatile text animation component that offers multiple animation types.
Cascade
Flicker
Blink
Blink
Expand
Expand
Rise
Rise
Glide
Glide
Elastic
Elastic
Float
Float
Installation Guide
1
Install Dependencies
Framer Motion
npm install framer-motion
2
Copy Component Code
Animated Text.tsx
TypeScript1"use client";
2
3import { FC, useRef, useEffect } from "react";
4import {
5 HTMLMotionProps,
6 motion,
7 useAnimation,
8 useInView,
9} from "framer-motion";
10
11type AnimationType =
12 | "blink"
13 | "rise"
14 | "expand"
15 | "glide"
16 | "cascade"
17 | "flicker"
18 | "elastic"
19 | "float";
20
21interface Props extends HTMLMotionProps<"div"> {
22 text: string;
23 type?: AnimationType;
24 delay?: number;
25 duration?: number;
26 custom?: number;
27}
28
29const animationVariants = {
30 blink: {
31 container: {
32 hidden: { opacity: 0 },
33 visible: (i: number = 1) => ({
34 opacity: 1,
35 transition: { staggerChildren: 0.05, delayChildren: i * 0.3 },
36 }),
37 },
38 child: {
39 visible: {
40 opacity: 1,
41 y: 0,
42 transition: {
43 type: "spring",
44 damping: 12,
45 stiffness: 100,
46 y: {
47 type: "keyframes",
48 times: [0, 0.5, 1],
49 values: [0, -10, 0],
50 },
51 },
52 },
53 hidden: { opacity: 0, y: 10 },
54 },
55 },
56 rise: {
57 container: {
58 hidden: { opacity: 0 },
59 visible: {
60 opacity: 1,
61 transition: { staggerChildren: 0.1, delayChildren: 0.2 },
62 },
63 },
64 child: {
65 visible: { opacity: 1, y: 0, transition: { duration: 0.5 } },
66 hidden: { opacity: 0, y: 20 },
67 },
68 },
69 expand: {
70 container: {
71 hidden: { opacity: 0, scale: 0.8 },
72 visible: {
73 opacity: 1,
74 scale: 1,
75 transition: { staggerChildren: 0.05, delayChildren: 0.2 },
76 },
77 },
78 child: {
79 visible: {
80 opacity: 1,
81 scale: 1,
82 transition: {
83 type: "spring",
84 damping: 15,
85 stiffness: 400,
86 scale: {
87 type: "keyframes",
88 times: [0, 0.6, 1],
89 values: [0, 1.1, 1],
90 },
91 },
92 },
93 hidden: { opacity: 0, scale: 0 },
94 },
95 },
96 float: {
97 container: {
98 hidden: {},
99 visible: (i: number = 1) => ({
100 transition: { staggerChildren: 0.03, delayChildren: 0.2 * i },
101 }),
102 },
103 child: {
104 hidden: {
105 y: 50,
106 opacity: 0,
107 },
108 visible: {
109 y: 0,
110 opacity: 1,
111 transition: {
112 duration: 0.5,
113 ease: "easeOut",
114 },
115 },
116 },
117 },
118 glide: {
119 container: {
120 hidden: {},
121 visible: (i: number = 1) => ({
122 transition: { staggerChildren: 0.03, delayChildren: 0.2 * i },
123 }),
124 },
125 child: {
126 hidden: {
127 y: 20,
128 opacity: 0,
129 },
130 visible: {
131 y: 0,
132 opacity: 1,
133 transition: {
134 duration: 0.5,
135 ease: [0.22, 1, 0.36, 1],
136 },
137 },
138 },
139 },
140 elastic: {
141 container: {
142 hidden: {},
143 visible: (i: number = 1) => ({
144 transition: { staggerChildren: 0.03, delayChildren: 0.2 * i },
145 }),
146 },
147 child: {
148 hidden: {
149 y: 50,
150 opacity: 0,
151 },
152 visible: {
153 y: 0,
154 opacity: 1,
155 transition: {
156 type: "spring",
157 stiffness: 400,
158 damping: 10,
159 },
160 },
161 },
162 },
163 cascade: {
164 container: {
165 hidden: {},
166 visible: {},
167 },
168 child: {
169 hidden: {
170 opacity: 0,
171 y: `0.25em`,
172 },
173 visible: {
174 opacity: 1,
175 y: `0em`,
176 transition: {
177 duration: 0.65,
178 ease: [0.65, 0, 0.75, 1],
179 },
180 },
181 },
182 },
183 flicker: {
184 container: {
185 hidden: {},
186 visible: {},
187 },
188 child: {
189 hidden: {
190 opacity: 0,
191 y: `0.35em`,
192 },
193 visible: {
194 opacity: 1,
195 y: `0em`,
196 transition: {
197 duration: 0.45,
198 ease: [0.85, 0.1, 0.9, 1.2],
199 },
200 },
201 },
202 },
203};
204
205export const AnimateText: FC<Props> = ({
206 text,
207 type = "elastic",
208 custom = 1,
209 className = "",
210 ...props
211}: Props) => {
212 const ref = useRef(null);
213 const isInView = useInView(ref, { once: false });
214 const ctrls = useAnimation();
215
216 useEffect(() => {
217 if (isInView) {
218 ctrls.start("visible");
219 } else {
220 ctrls.start("hidden");
221 }
222 }, [isInView, ctrls]);
223
224 const letters = Array.from(text);
225 const { container, child } = animationVariants[type];
226
227 if (type === "cascade" || type === "flicker") {
228 return (
229 <h2
230 ref={ref}
231 className={`mt-6 text-3xl font-bold text-black dark:text-neutral-100 py-4 px-4 md:text-4xl ${className}`}
232 >
233 {text.split(" ").map((word, index) => {
234 return (
235 <motion.span
236 className="inline-block mr-[0.25em] whitespace-nowrap"
237 aria-hidden="true"
238 key={index}
239 initial="hidden"
240 animate={isInView ? "visible" : "hidden"}
241 variants={container}
242 transition={{
243 delayChildren: index * 0.13,
244 staggerChildren: 0.025,
245 }}
246 >
247 {word.split("").map((character, index) => {
248 return (
249 <motion.span
250 aria-hidden="true"
251 key={index}
252 variants={child}
253 className="inline-block -mr-[0.01em]"
254 >
255 {character}
256 </motion.span>
257 );
258 })}
259 </motion.span>
260 );
261 })}
262 </h2>
263 );
264 }
265
266 return (
267 <motion.h2
268 ref={ref}
269 style={{ display: "flex", overflow: "hidden" }}
270 role="heading"
271 variants={container}
272 initial="hidden"
273 animate={ctrls}
274 custom={custom}
275 className={`mt-6 text-3xl font-bold text-black dark:text-neutral-100 py-4 px-4 md:text-4xl ${className}`}
276 {...props}
277 >
278 {letters.map((letter, index) => (
279 <motion.span key={index} variants={child}>
280 {letter === " " ? "\u00A0" : letter}
281 </motion.span>
282 ))}
283 </motion.h2>
284 );
285};
286
3
Final Steps
Update Import Paths
Make sure to update the import paths in the component code to match your project structure. For example, change @/components/ui/button
to match your UI components location.
Props
Name | Type | Default | Description |
---|---|---|---|
text | string | "" | The text content to be animated. |
type | "cascade" | "flicker" | "blink" | "expand" | "rise" | "glide" | "elastic" | "float" | "cascade" | Animation style to apply to the text. |
className | string | "" | Additional CSS classes to apply to the component. |
delay | number | 0 | Delay before animation starts in milliseconds. |
duration | number | 0.5 | Duration of the animation in seconds. |
staggerChildren | number | 0.05 | Time between each character's animation for cascade effects. |
once | boolean | true | If true, animation plays only once when in view. |
fontSize | string | "2xl" | Font size using Tailwind CSS size classes. |
fontWeight | string | "bold" | Font weight using Tailwind CSS weight classes. |
color | string | "" | Text color (uses theme colors if not specified). |
Examples
Modern UI Library
Build beautiful interfaces with ease
Responsive Design
Ensure your UI looks great on all devices
Build fast and beautiful
Let's make web beautiful
Start building beautiful interfaces faster than ever before