Text
Animated Text
Character-level text animation — typewriter, scramble and flowing gradient as one component's variants.
Preview in your theme
Loading preview…
Installation
npx shadcn@latest add https://ui.zyeon.ai/r/animated-text.jsonPrompt
The prompt behind this component — paste it into your AI assistant to recreate or adapt it.
Build a React + TypeScript + Tailwind "AnimatedText" component.
Contract
- Export a forwardRef span extending React.HTMLAttributes<HTMLSpanElement>.
- Props: text (string), variant = "typewriter" | "scramble" | "gradient"
(default "typewriter"), speed (ms per character step, default 45),
delay (ms before starting, default 0).
Behavior
- Keep ONE piece of state: progress (how many characters are settled). A
setTimeout(delay) arms a setInterval(speed) that increments progress and
self-clears at text.length; both timers are cleaned up on unmount.
- The displayed string is DERIVED at render, never stored:
- typewriter: text.slice(0, progress) plus a blinking caret span.
- scramble: settled prefix + the remaining characters replaced by glyphs
from a symbol set. Use a deterministic hash of (progress, index) instead
of Math.random so render stays pure (React Compiler purity rule) — the
tail still re-scrambles every tick because progress changes.
- gradient: no timers at all — a CSS keyframe slides a 200%-wide
background gradient across the glyphs via background-clip: text.
- Reset progress when text/variant/speed/delay change using the
adjust-state-during-render pattern (compare a prev key, no effects).
- Read prefers-reduced-motion via useSyncExternalStore on matchMedia
(server snapshot false); when reduced, render the full text immediately
and stop the gradient loop with motion-reduce:[animation:none].
Rendering & styling
- Semantic tokens only. The gradient runs from-foreground via-primary/50
to-foreground — the 50% alpha on the middle stop guarantees a visible
sweep even on monochrome themes where primary equals foreground
(e.g. shadcn's default zinc); caret is bg-current.
- Accessibility: the animated glyphs are noise for screen readers — put the
real text in aria-label on the wrapper and aria-hidden on the animated
span. The gradient variant keeps real DOM text.
- Ship the gradient @keyframes via a React 19 hoisted
<style href precedence> tag — no Tailwind config edits, dedupes by href.
Customization levers
- Pace: speed 30–80ms reads well for headlines; longer text wants faster.
- Scramble glyph set: swap the symbol string for a domain flavor
(binary "01", katakana, hex) without touching the engine.
- Gradient hue: change via-primary/50 to another token (via-chart-2/60
etc.) — keep some alpha so monochrome themes still show the sweep; tune
the 3s duration for a calmer or flashier pace.
- Caret: restyle the w-px bg-current span (block cursor: w-[0.5em]), or
remove it for a subtitle feel.
- Looping: wrap with a key that increments on an interval to replay, or
cycle through an array of texts at the call site.Concepts
- Derived display, single state — only the settled-character count lives in state; the visible string is computed at render, so the three variants share one tiny engine instead of three text buffers.
- Deterministic scramble — a pure hash of
(progress, index)picks each unsettled glyph; render stays pure for the React Compiler while the tail still re-rolls every tick. - Screen-reader honesty — assistive tech gets the final text at once via
aria-label; the animated intermediate frames arearia-hiddennoise it never hears. - CSS-only gradient — the gradient variant is zero-JS after mount:
background-clip: textplus a background-position keyframe, stopped under reduced motion. - Adjust-state-during-render — prop changes reset the animation by comparing a previous key during render (the React-documented pattern), avoiding effect-driven state cascades.
360 Spin Viewer
A turntable image sequence scrubbed by drag, touch and arrow keys — wrapping at both ends, preloaded behind a progress state, and skipping frames that fail.
Word Rotate
A jitter-free rotating word inside a headline — cycles through a word list with a slide or fade transition and never shifts layout width.