Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Text

Pro

Typing Text for React

Text typed out one character at a time behind a blinking caret, or several lines typed and deleted in turn. For React with Base UI, when a hero or a prompt should feel written live.

Framework

Typing Text types a line out one character at a time behind a caret, the way a person would: each keystroke's wait varies a little, and the caret blinks only while it waits. Give it several lines and it types one, pauses, deletes it and types the next, round and round.

Use it for a hero line that cycles through what a product is for, a command in a terminal mock-up, or a prompt being written. To swap whole words in place instead, use Flip Words or Rotating Text; to delete and correct a line, Backspace Text. A small timer moves it one step at a time and a CSS keyframe animation blinks the caret, with no animation library; with reduced motion each line shows whole.

Preview width

Installation

Part of Pro
Pro unlocks the code and one-line install of every Pro button and text effect, plus the MCP for your AI editor.
Have Pro already? Sign in to open it.Opens here as soon as you're Pro.

Usage

import { TypingText } from "@/components/ui/typing-text";
<TypingText text={["Components you own.", "Ship it this afternoon."]} />

Demos

Cursor

cursor is the caret's shape: bar, the default, block or underscore, drawn in the text's colour, or none. Style it further through data-slot="typing-text-cursor".

Preview width

Colors

colors gives each line its own colour, in turn, any CSS colour or theme variable. The text sits inline in a sentence like any other word.

Preview width

Terminal

trigger="view" waits, caret blinking, until the text scrolls into view. delay is the wait before the first character, speed the average time per character, and onComplete is called once the last line is typed: here it shows the command's output.

Preview width

Accessibility

Screen readers read every line once, in full, from a visually hidden copy, never the half-typed characters; the typed text and the caret are hidden from them. The caret blinks once a second, well under the three flashes a second that can trigger seizures, and stops with reduced motion, where each line shows whole.

FAQ

How do several lines cycle?

Pass an array to text. Each line is typed, stays for pause (1800 ms by default), is deleted at deleteSpeed, and the next one is typed. After the last line it starts over; with loop={false} it stops on the last line, typed.

Why does the typing speed vary?

A person never types at an even pace, so each keystroke waits speed give or take jitter (half of it by default). The variation is worked out from the character's place, not drawn at random, so it types the same way on every visit. jitter={0} types like a metronome.

Why doesn't the caret blink while typing?

Because a real one doesn't: it stays solid while characters arrive and blinks once the typing waits, at a pause, at the end, or before it starts.

Will the text around it move as it types?

It grows like any text, so in a centred heading the line re-centres as it types. To hold the layout, give its container a fixed width or a min-h that fits the longest line.

What do screen readers hear with several lines?

Every line once, one after the other, without the typing. End each line with punctuation if it should be read as its own sentence.

What does it show without JavaScript?

The first line, whole, with its caret after it.

What happens with reduced motion?

Each line shows whole, swapping when the next one would be typed, and the caret holds still.

API Reference

TypingText

<span> data-slot="typing-text"

PropType
textstring | string[]

The text, or several lines typed and deleted in turn.

Type
string | string[]
colors?string[]

Colours the lines take in turn, any CSS colour; the text's own colour when unset.

cursor?"bar" | "block" | "underscore" | "none"

The caret after the text. @default "bar".

Type
"bar" | "block" | "underscore" | "none"
Default
"bar"
delay?number

The wait before the first character, in milliseconds. @default 0.

Default
0
deleteSpeed?number

The time to delete one character, in milliseconds. @default 30.

Default
30
jitter?number

How much each keystroke's wait varies, from 0 (even) to 1. @default 0.5.

Default
0.5
loop?boolean

Whether several lines start over after the last; a single line is typed once.

Default
true
onComplete?() → void

Called once the typing is over: the last line typed, when it doesn't loop.

Returns
void
pause?number

How long a typed line stays before it's deleted, in milliseconds. @default 1800.

Default
1800
speed?number

The time to type one character, on average, in milliseconds. @default 60.

Default
60
trigger?"mount" | "view"

When the typing starts: as soon as the page shows it, or once it scrolls into view. @default "mount".

Type
"mount" | "view"
Default
"mount"
render?ReactElement | ((props: object, state: object) => ReactElement)

Replace the host element or compose it with another component.

Type
ReactElement | ((props: object, state: object) => ReactElement)
className?string

Merged with the part's classes.

AttributeType
data-state?string
CSS variableType
--typing-text-colorstring

The colour of the current line (from colors).

All 97 text effects