Text Animate React component for Tailwind CSS v4
v1.0.0Added in 1.10.0
Animated text for headlines and copy that reveals by word, character or line with a fade, blur, slide, scale or typewriter effect.
Scroll the text into view and it reveals itself piece by piece: words blur into focus, lines slide up, characters fade in one after another, or a typewriter types it out with a blinking caret. The space is reserved before it plays, so nothing around it shifts. Screen readers get the full sentence once, never letter by letter, and with reduced motion on the text simply appears.
Text Animate is a Pro React component in the React effect components category, written in TypeScript for React 19 and Tailwind CSS v4. It installs as source with npx wingo-ui@latest add text-animate, together with Motion presets and UIProvider and the npm package motion.
Add to a project
Requirements: React 19 and Tailwind CSS v4, in Next.js (App Router or Pages), Vite or React Router. Installation guide · Next.js setup · Vite setup
npx wingo-ui@latest add text-animatePro item: the CLI needs a Pro account. See plans
Usage
Import TextAnimate from @/components/ui/text-animate.
import { TextAnimate } from "@/components/ui/text-animate"
export function Hero() {
return (
<section className="mx-auto max-w-2xl text-center">
<TextAnimate as="h1" effect="blur" by="word" trigger="mount" className="text-5xl font-semibold tracking-tight">
Ship polished interfaces in an afternoon
</TextAnimate>
<TextAnimate effect="slide-up" by="line" trigger="mount" delay={400} stagger={100} className="mt-4 text-lg text-muted-foreground">
{"Copy the source, keep full control.\nEvery component works on phones first."}
</TextAnimate>
</section>
)
}
// A typewriter with a caret:
// <TextAnimate effect="typewriter" speed={40}>npx wingo-ui add text-animate</TextAnimate>Props
children*default"Interfaces that feel alive"stringThe text, as a plain string. Line breaks (\n) start a new line and mark the segments for by="line".
asdefault"p""h1" | "h2" | "h3" | "p" | "span" | "div"The element to render, so a headline stays a real heading for SEO and screen readers.
effectdefault"blur""fade" | "blur" | "slide-up" | "slide-down" | "scale" | "typewriter"How each piece enters. blur sharpens from an 8px blur while rising slightly; typewriter types character by character with a caret.
bydefault"word""word" | "char" | "line"The unit that animates. char keeps whole words together so a line never breaks mid-word. Ignored by the typewriter, which always types by character.
triggerdefault"in-view""mount" | "in-view"mount plays as soon as the page loads; in-view waits until the text scrolls into view.
oncedefaulttruebooleanWith in-view, plays the first time only. Turn it off to hide the text again when it leaves the screen and replay it on the way back.
amountdefault0.4numberWith in-view, how much of the text (0 to 1) has to be visible before it plays.
delaydefault0numberMilliseconds before the first piece starts. Handy for a subtitle that follows its headline.
staggerdefault40numberMilliseconds between one piece and the next. Try 15 to 25 for characters and 80 to 120 for lines.
speeddefault35numberTypewriter only: milliseconds per character, spaces included.
caretdefaulttruebooleanTypewriter only: shows a caret that follows the last typed character and stays at the end.
caretBlinkdefaulttruebooleanTypewriter only: makes the caret blink. It never blinks with reduced motion on.
animatedefault""booleanControls playback yourself and ignores trigger: false hides the text instantly, true plays it. Turn it off and on again to replay. Unset (Default in the playground) follows trigger.
onComplete() => voidCalled once the last piece has finished entering, again after every replay.
classNamesPartial<Record<"segment" | "caret", string>>Extra classes for each animated piece and for the typewriter caret.
classNamestringExtra classes for the root element: font size, weight, color and alignment go here.
refRef<HTMLElement> (a useRef object or an (el) => void callback)The root element (the h1, p or whichever tag as picks).
Parts
TextAnimateEffect
typeThe effect names: "fade" | "blur" | "slide-up" | "slide-down" | "scale" | "typewriter".
TextAnimateBy
typeThe animated unit: "word" | "char" | "line".
TextAnimateTrigger
typeWhen it plays: "mount" | "in-view".
TextAnimateTag
typeThe elements the as prop accepts: "h1" | "h2" | "h3" | "p" | "span" | "div".
TextAnimateSlot
typeThe keys of classNames: "segment" | "caret".
TextAnimateState
typeThe playback state, also written to the root as data-state: "idle" before it plays, "animating", then "done".
TextAnimateProps
typeThe props of TextAnimate, plus every attribute of the rendered element.
Examples
Hero headline
An h1 that blurs in word by word, with a subtitle sliding up after a 450ms delay.
Line by line
by="line" splits on line breaks; a longer stagger lets each line land before the next one.
Typewriter
Types one character every 45ms while the caret follows along, then keeps blinking at the end.
Character fade
by="char" with a short stagger; words never break across lines while they fade in.
Controlled replay
The animate prop starts it on demand, and onComplete reports when the last word has landed.
Files
- components/ui/text-animate.tsx
FAQ
Is the React Text Animate component free?
The preview, props and docs are free; copying the source needs a Pro plan. See plans.
How do I install Text Animate?
Run npx wingo-ui@latest add text-animate. It also adds the Wingo UI items it builds on (Motion presets and UIProvider) and the npm package motion. With shadcn, add the @wingo-ui registry with your API key, then run npx shadcn@latest add @wingo-ui/text-animate.