Appica UIUI 1.0.0

Text Animate

A text animator that works by character, word, or line — typewriter, scramble, wave, and more.

Animate any text

Usage

TextAnimate splits a string into units — characters, words, or lines — and drives every unit from a single progress value (0 → 1). One small engine therefore covers many effects: it ships seven presets (typewriter, scramble, rise, highlight, wave, flip, shimmer) and accepts a custom function for anything else.

It is deliberately headless and font-agnostic: it animates only transform, opacity, and the displayed glyphs — never font-size, font-weight, line-height, or letter-spacing. So it inherits whatever typography you set, and multi-line text wraps and breaks naturally.

Two ways to drive it

The component never listens to scroll, viewport, or page load on its own — that keeps it composable. You either let its built-in clock play the animation, or you own the timeline:

When you pass progress, the internal clock is disabled and the component is fully controlled — wire it to a scroll listener, an IntersectionObserver, a Motion MotionValue, or a slider. When you omit progress, an opt-in requestAnimationFrame clock plays it once (duration, delay) or forever (loop).

Examples

Typewriter

The classic effect: characters reveal one-by-one with a blinking caret on the typing edge. Hidden characters take no space, so the line grows as it types.

Scramble

Each character cycles through random glyphs before locking onto its target — the "decode" look. Whitespace is left intact so word boundaries stay stable while the text resolves. Pairs nicely with a monospace font.

Rise

Each unit slides up from behind a clip edge, so the text wipes into view from its own baseline rather than just translating — a masked reveal that's tedious to wire up by hand. It defaults to a per-character cascade; switch to by="word" or by="line" for a chunkier reveal.

Reveal on scroll into view

highlight ramps each word from dimmed to full. Here an IntersectionObserver plays the reveal each time the paragraph scrolls into the panel (and resets it on the way out) — the observer is the trigger, the component just animates. No animation library required.

Drive it yourself

progress accepts any 0 → 1 value, so you can scrub the animation from a slider, a gesture, or app state — wire it to a scroll position for a true scrub-as-you-scroll effect, or to any source you like.

Continuous effects

wave and shimmer are continuous: their presets loop the clock automatically, so they animate on mount with no driver wiring. wave ripples each character vertically (amplitude in em, so it scales with the font); shimmer sweeps a bright band along the string.

Custom effects

Pass a function instead of a preset name. It receives each unit's local progress and a context object, and returns inline style (and/or replacement content). Everything the presets do, you can do — here a per-character blur-and-rise entrance.

For continuous effects, read ctx.globalProgress (the raw, un-staggered driver value) and ctx.index instead of the first argument — that is how wave and shimmer phase each character.

Multiple lines

Use \n for explicit line breaks. Words still wrap within each line, and the stagger flows across every line in reading order.

RTL

Every Appica UI component supports right-to-left layouts out of the box. Set the dir attribute on a container (commonly your <html> element) so CSS logical properties resolve correctly, and wrap your tree in DirectionProvider so direction-aware behavior follows the same direction.

Word and line units follow the resolved direction automatically. For setup details and caveats, see the RTL guide.

صمّم واجهات جميلة بسرعة فائقة

API reference

Renders a <span> wrapping the animated text. The full string is always present as an sr-only copy for assistive tech; the animated glyphs are aria-hidden.

Forwards ref, className, and any other <span> attributes. The root is inline-block — override display via className (e.g. block) if you need it.

The effect function

A custom effect is (progress, ctx) => { style?, className?, content? }, called once per unit per frame:

Return style/className to animate the glyph and/or content to replace the displayed text (how scramble and typewriter mutate characters).

Accessibility

  • The complete text is always rendered as an sr-only copy, so screen readers announce it once, in full — regardless of animation state. The animated glyphs are aria-hidden.
  • The animation honours prefers-reduced-motion (and ReducedMotionProvider): the built-in clock snaps straight to the final frame, the caret stops blinking, and motion-heavy presets (wave, flip, shimmer) render their static, fully-legible state.
  • A controlled progress is not overridden by reduced motion — a scroll-linked reveal keeps working — but the motion-heavy presets still drop their transforms for those users.
  • by="char" breaks the contextual shaping of cursive scripts (e.g. Arabic); use by="word" or by="line" there.
  • Because every unit re-renders each frame, keep animated strings to headline/sentence length rather than long bodies of text.

© 2026 Appica UI. A free component library, crafted by the Appica team.