TypingLines

A React typing animation component that types each line, holds, then deletes it. For headlines and terminals.

TypingLines playground

Word reveals usually pair with caret "none" - nothing is pending between words.

Install TypingLines

1. New project? One command installs the package and wires everything - see Installation:

bash
pnpm dlx zyncat-ui init

2. Import the component - it loads its own stylesheet:

tsx
import { TypingLines } from '@zyncat/ui/typing-lines';

Usage

tsx
import { TypingLines } from '@zyncat/ui/typing-lines';
 
<TypingLines lines={['Design every state.', 'Make every motion interruptible.']} />

Compose TypingLines in your application. No Tailwind or external styling library is required; every value resolves from Zyncat UI's token vocabulary.

TypingLines props

TypingLines

PropTypeDefaultDescription
...htmlAttributesHTMLAttributes—Standard <span> attributes (aria-*, data-*, title, ...) forwarded to the root.
lines*string[]—The lines to type, in order; the sequence restarts once the last one has been deleted.
unitTypingUnit'character'Whether the line arrives one character or one whole word at a time.
caretTypingCaret'line'Caret shape. It holds solid while characters land and blinks only once the line is idle.
speednumber1Multiplies the typing rate; sampled live on every frame.
classNamestring—Extra class(es) merged onto the root.
styleTypingLinesStyle—Inline styles merged onto the root.

TypingLinesStyle

PropTypeDefaultDescription
--typing-lines-inkstring | number—`--typing-lines-ink` - Letter ink. Default: `var(--text-strong)`.
--typing-lines-caret-inkstring | number—`--typing-lines-caret-ink` - The caret. Default: `var(--accent)`.
--typing-lines-sizestring | number—`--typing-lines-size` - Letter size. Default: `var(--size-title)`.
--typing-lines-weightstring | number—`--typing-lines-weight` - Letter weight. Default: `var(--weight-regular)`.
--typing-lines-leadingstring | number—`--typing-lines-leading` - Line height, unitless. Default: `1.4`.
--typing-lines-blinkstring | number—`--typing-lines-blink` - The caret's blink period. Default: `1080ms`.
--typing-lines-caret-gapstring | number—`--typing-lines-caret-gap` - Space between the last glyph and the caret. Default: `0.12em`.

Frequently asked questions

Import it per subpath and pass the lines: import { TypingLines } from '@zyncat/ui/typing-lines', then <TypingLines lines={['Design every state.', 'Ship the polish.']} />. It is a client component, so it drops straight into the Next.js App Router; link @zyncat/ui/styles.css once at the root for the tokens.

Only a limited one. The classic CSS typewriter animates a width in steps() behind a border-right caret, so it needs one fixed-width line of monospace and it cannot delete a line or move on to the next. Here CSS owns the look - ink, size, weight, leading, caret gap and the step-end blink all read from --typing-lines-* custom properties - while the character timing, the deletion and the line sequence are driven in JavaScript.

No - it is a React component that types live DOM text on a web page, not a GIF, a Lottie file, or an After Effects, Premiere Pro, DaVinci Resolve, Canva or CapCut preset, so the words stay selectable text rather than pixels. The playground on this page is the generator: set the unit, caret and speed, then copy the JSX from the Code tab.

Yes. lines is the equivalent of the typed.js strings array, and the sequence loops on its own with no loop flag, so you do not need typed.js, react-simple-typewriter or react-type-animation alongside it. It is a React 19 component with zero runtime dependencies, not a wrapper around a standalone JS library.

Yes. unit switches between 'character' - one letter every 54ms, the default - and 'word', where a whole word fades and rises into place at a time. caret picks 'line', 'block', 'underscore' or 'none', and 'none' suits word reveals, where nothing is pending between words; speed multiplies the whole cycle, including the 2.4s hold on a finished line, and is sampled live on every frame, so moving a slider retimes a line already being typed.

Yes. The full current line is rendered as real text in a visually hidden label for screen readers while the animated text and the caret are aria-hidden, so assistive tech reads one sentence instead of a stream of letters. Under prefers-reduced-motion the loop never starts and the first line shows complete and still, and the animation pauses on its own whenever the element scrolls out of view or the tab is hidden.

Set in Geist & Newsreader — animated by the house engineZyncat UI · Rev 0.11 · MIT · Built by Tabsir Ahammed · Source on GitHub