Skip to content

Typing Animation

Text that types itself out one character at a time, with an optional blinking cursor and an optional loop. The full text is in the page from the start.

Motionv0.1.0experimentalWCAG 2.2 AAView spec

Optional, and kept apart.

Nothing here is included in a project unless you add it, and the plain component it builds on is unchanged. This effect is decoration: it is hidden from screen readers, stands still for visitors who prefer reduced motion, and can be paused. Use Still on a preview to see that version.

Ship the interface your users can actually use.
import { TypingAnimation } from "@rdloom/react";

export default function TypingAnimationBasicExample() {
  return (
    <div className="flex w-full justify-center">
      <TypingAnimation className="text-xl font-medium">Ship the interface your users can actually use.</TypingAnimation>
    </div>
  );
}

Installation

npx rdloom add typing-animation

Copies the source into src/components/rdloom. Edit it freely: rdloom upgrade merges later versions into your changes.

It also adds rdloom-motion.css next to your tokens and imports it from the tokens file, once: no setup, and no inline styles. The plain components you already use are untouched.

Use another registry client
npx shadcn@latest add https://rdloom.vimalbhatt.com/r/typing-animation.json

Works, but without upgrade tracking, and you import the motion CSS yourself.

Usage

import { TypingAnimation } from "@rdloom/react";

<div className="flex w-full justify-center">
  <TypingAnimation className="text-xl font-medium">Ship the interface your users can actually use.</TypingAnimation>
</div>

Looping

npx rdloom add typing-animation
import { TypingAnimation } from "@rdloom/react";

// Loops after a short pause. Use the Still switch, or isPaused, to stop it.
export default function TypingAnimationLoopingExample() {
  return (
    <div className="flex w-full justify-center">
      <code className="rounded-md bg-[var(--rd-color-surface-subtle)] px-3 py-2 text-sm">
        <TypingAnimation loop speed={90}>
          npx rdloom add typing-animation
        </TypingAnimation>
      </code>
    </div>
  );
}

API Reference

Defined by the spec. Components also accept the props of the React Aria component they wrap.

PropTypeDefault
childrenrequired

The text to type.

stringnone
speed

Milliseconds per character.

number70
delay

Seconds to wait before typing starts.

number0
cursor

Shows a blinking cursor after the text.

booleantrue
loop

Types the text again after a short pause, once it has finished.

booleanfalse
isPaused

Stops the animation and shows the finished text. Moving content that lasts more than five seconds should be stoppable.

booleanfalse

Accessibility

Role text, WCAG 2.2 AA. Tested with axe and keyboard tests; screen reader checks are in the audit checklist.

Keyboard

Not interactive.

Screen readers announce

  • The full text is read once, immediately; the typing is not announced

What your code must do

  • The full text is present as visually hidden text from the first render, so assistive technology reads it once, never letter by letter
  • With no JavaScript, or with reduced motion, the finished text is shown at once
  • Decoration only: the animated layers are hidden from assistive technology and never take focus
  • Stands still for visitors who ask for less motion (prefers-reduced-motion), and can also be shown still with the rdm-still class or isPaused
  • In forced-colors (high contrast) mode the text is drawn in the system colours
  • Does not flash: nothing changes more than three times in a second (WCAG 2.3.1)
  • Optional: it is a separate component, so projects that do not add it carry none of its code

Guidelines

Use it when

  • A short tagline or terminal-style line in a hero
  • Showing a command being typed

Avoid it when

  • Text people must read the moment the page loads
  • Long paragraphs

Don't

  • Looping text that is also the only place a message appears
  • Typing speeds so slow the text takes many seconds to finish

Design tokens

The semantic tokens this component uses. Change them once and every component follows; see Design tokens.

  • --rd-color-text-default
  • --rd-color-text-muted