Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Text

Free

Text Generate Effect for React

Text that appears word by word and sharpens into focus, as if it were being generated. For React with Base UI, when a reply or a paragraph should feel written as people watch.

Framework

Text Generate Effect shows a text word after word in quick succession, like a reply coming from a model: each word appears at once where it stands, still soft, then slowly sharpens into focus. Nothing moves, so the paragraph keeps its shape from the first word to the last.

Use it for an assistant's reply, a generated summary or a paragraph under a hero. For a headline whose words drop in through a heavier blur, use Blur Text; for a sentence that arrives at the pace of speech, Writing Text; to type a line out a character at a time, Typing Text. The motion is a CSS keyframe animation the install adds to your stylesheet, each word's opacity running ahead of its blur, delayed by its place in the text, with no animation library. With reduced motion the text is simply there.

Preview width

Installation

Sign in to get your install command
Free with an account. It carries your token, so the CLI installs everything in one go.

Usage

import {
  TextGenerateEffect,
} from "@/components/ui/text-generate-effect";
<p>
  <TextGenerateEffect text="Each word appears in turn, then comes into focus." />
</p>

Demos

Chat

In a reply bubble, a shorter duration (600 ms) and stagger (40 ms) keep pace with a quick read. The bubble has its final size from the start: every word is already in place, just not yet shown.

Preview width

Fade

blur={false} leaves out the blur, so each word only fades in.

Preview width

Accessibility

Screen readers read the whole text once, as plain text: the appearing words are hidden from them, and a visually hidden copy carries it. Words wrap as usual, line breaks are kept, and the text keeps its direction on a right-to-left page. With reduced motion every word is there and sharp from the start.

FAQ

How is it different from Blur Text?

Blur Text moves each word into place and is made for a headline. Here the words don't move, follow each other faster (80 ms apart rather than 150) and sharpen more slowly (over a second), so a whole paragraph reads as if it were being written.

Does the paragraph reflow while it appears?

No. Every word takes its place from the start and only its opacity and blur change, so the text around it, and the box it's in, never move.

Can it show a reply while it streams in?

It's made for a text that has arrived: each word waits for its place in the text times stagger, counted from when it first renders, so words added later would wait behind the ones already shown. Pass the reply once it's complete, or one finished message at a time.

How long does a paragraph take?

A stagger per word after the first, then one duration: at the defaults, 80 ms and 1000 ms, a 25-word paragraph is all there in three seconds. Each word is readable well before it's sharp, at about 40% of its duration.

When does the animation play?

With trigger="mount", the default, as soon as the page shows it: the animation runs from CSS alone, before the page's script loads. With trigger="view" it waits until a quarter of the text has scrolled into view, then plays once.

How do I run something after it finishes?

Pass onComplete: it's called once, when the last word is in focus, such as to show a reply's actions after it.

What happens with reduced motion?

No fade and no blur: the text is there from the start, fully readable.

API Reference

TextGenerateEffect

<span> data-slot="text-generate-effect"

PropType
textstring

The text. Its line breaks (\n) are kept.

blur?boolean

Whether each word comes into focus from a blur; false only fades it in. @default true.

Default
true
duration?number

How long one word takes to come into focus, in milliseconds; it's there in the first half, sharp by the end.

Default
1000
onComplete?() → void

Called once the last word is in focus.

Returns
void
stagger?number

The time between one word appearing and the next, in milliseconds. @default 80.

trigger?"mount" | "view"

When it plays: as soon as it's on the page, or once it scrolls into view.

Type
"mount" | "view"
Default
"mount"
render?ReactElement | ((props: object, state: object) => ReactElement)

Replace the host element or compose it with another component.

Type
ReactElement | ((props: object, state: object) => ReactElement)
className?string

Merged with the part's classes.

AttributeType
data-last?string
data-view?string

"in" when visible is true, otherwise "out".

CSS variableType
--text-generate-effect-blurstring

The blur each word starts from (8px).

--text-generate-effect-durationstring

One word's focus.

--text-generate-effect-staggerstring

The time between one word and the next.

All 97 text effects