TextAnimation

Five ways a piece of text or a number arrives — reveal, typing, rotating, counting, rolling — on one clock.

Open Source

Installation

TextAnimation ships with the library — install it once, then import:

import { TextAnimation } from "@delacour/react-native-ui/text-animation";

Or copy the source into your project, to own and edit it:

bunx delacour@latest add text-animation

Usage

app/index.tsx
import { TextAnimation } from "@/components/ui/text-animation";
import { View } from "react-native";

export default function Example() {
  return (
    <View className="flex-1 justify-center p-4">
      <TextAnimation effect={{ kind: "slide", from: "down" }} size="3xl" weight="bold">
        Ship the release before lunch
      </TextAnimation>
    </View>
  );
}

The root reveals a string, and the four parts hang off it. Every part takes Text's axes — variant, size, weight, color, align, transform — and joins the Text cascade, so a TextAnimation inside a muted Text comes out muted. className is applied to each piece of text the part draws; wrap the part in a View to place it.

Anatomy

PartWhat it does
TextAnimationReveals a string unit by unit — by word, character or line — with a fade, slide or scale
TextAnimation.TypingTypes a phrase, or cycles several, with a blinking caret and an optional erase
TextAnimation.RotatingSwaps one phrase for the next in place — one word inside a sentence
TextAnimation.CountingTweens a number to a new value, formatted
TextAnimation.RollingAn odometer: each digit is a wheel that rolls to its new digit

Reveal

Reveal by word
Reveal by character
<TextAnimation effect={{ kind: "fade" }}>Fades in, word by word</TextAnimation>
<TextAnimation effect={{ kind: "slide", from: "down", distance: 16 }}>Rises into place</TextAnimation>
<TextAnimation effect={{ kind: "scale", from: 0.4 }} order="center" split="character">
  Delacour
</TextAnimation>
  • split — word (the default), character or line. A character split holds each word on one line, so a word never breaks mid-glyph. A line split reads the breaks the platform chose.
  • stagger — the delay between consecutive units: 40 ms for characters, 90 ms otherwise.
  • order — forward, reverse, center (from the middle outwards) or random, which is seeded by the text so a replay is the same shuffle.
  • isActive — false holds the text hidden; flipping it to true plays from the start. Change the key to replay.
  • onFinished — fires once when the last unit lands, never for a run that was interrupted.

Typing

Typing
<TextAnimation.Typing caret={{ kind: "bar" }} size="2xl">
  {["Design systems that ship.", "Native apps that feel native."]}
</TextAnimation.Typing>

One phrase types once and holds. Several cycle: each is typed at speed characters a second, held for holdMs, then erased at eraseSpeed. eraseSpeed={0} skips the erase and the next phrase replaces the last. Speeds, not durations — a phrase twice as long takes twice as long.

The caret is bar, block or none, and it takes the text's own colour. It blinks only while waiting; while characters land it is solid.

Rotating

Rotating
<View className="flex-row items-end">
  <Text size="2xl">Built for </Text>
  <TextAnimation.Rotating phrases={["fast", "small", "remote"]} size="2xl" transition={{ kind: "slide" }} />
  <Text size="2xl"> teams</Text>
</View>

The phrase changes every intervalMs, crossing over in transitionMs with a fade or a vertical slide. reserve="widest" — the default — holds the widest phrase's width, so the words around it never move. Use reserve="current" for a word that ends a line.

Counting

Counting
<TextAnimation.Counting format={{ prefix: "$", decimals: 2 }} value={balance} />

format writes the number: decimals, groupSeparator ("," by default, "" for none), decimalSeparator, prefix and suffix. A negative takes a true minus ahead of the prefix — −$5. NaN and the infinities are an em dash.

A new value tweens from whatever is on screen — not from from, which is only the first mount's start. animateOnMount={false} shows the value at once and tweens only later changes.

Rolling

Rolling
<TextAnimation.Rolling value={odometer} />

Each digit rolls the short way to its new digit, in the direction the value moved: 9 → 0 on the way up rolls forward through the wrap, not back through 8…1. When the number grows a digit — 999 to 1,000 — the new wheel rolls up from 0. Wheels start least-significant first, stagger ms apart. Separators, the sign, the prefix and the suffix stay put.

Why nothing reflows

Every part lays its text out before anything moves, and animates only opacity and transform:

  • A reveal's units are siblings in a wrapping row, laid out at full size and invisible, so a paragraph wraps once and never again.
  • Typing lays out the whole phrase and shows it as the typed count passes each character. The box keeps the tallest phrase's height.
  • Rotating holds its widest phrase's width; Counting holds the wider of its start and its target.
  • Both numeric parts use tabular figures, so no digit is wider than another.

What a screen reader gets

The final plain text, once. Each part is a single text element whose label is the whole revealed string, the last typed phrase, the current rotating phrase, or the formatted target of a count or a roll — never a half-typed word or an in-flight digit. Rotating and Counting do not announce a change: a reader interrupted every two seconds is no help.

Reduced motion

Under the system's reduce-motion setting, or isMotionCalm on DelacourProvider, every part shows its final text on the first frame:

PartShows
TextAnimationThe whole text, at rest; onFinished still fires
TextAnimation.TypingThe last phrase, typed in full, with a steady caret
TextAnimation.RotatingThe first phrase, held — a rotating word is a loop
TextAnimation.CountingThe value at once — it is information
TextAnimation.RollingEvery wheel at its digit

API Reference

TextAnimation

Prop

Type

Every part also takes variant, size, weight, color, align, transform, className, allowFontScaling, maxFontSizeMultiplier, testID, nativeID and accessibilityHint.

TextAnimation.Typing

Prop

Type

TextAnimation.Rotating

Prop

Type

TextAnimation.Counting

Prop

Type

TextAnimation.Rolling

Prop

Type

On this page