Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Text

Free

Splitting Text for React

Text split into characters, words or lines that slide into place one after another. For React with Base UI, when a headline should assemble itself as the page loads.

Framework

Splitting Text breaks a line into characters, words or lines and slides each one into place after the last: from the end of the line by default, or from its start, above or below. It plays once, as soon as the page shows it or when it scrolls into view, and a delay lets a second line wait for the first.

Use it for a hero headline, a section title or a few short lines that should assemble themselves. For words that come into focus from a blur, use Blur Text; for words that arrive at the pace of speech, Writing Text; for letters that unfold, Paper Fold Text. The motion is one CSS keyframe animation the install adds to your stylesheet, delayed for each piece by its place in the text, with no animation library. With reduced motion the text is simply there.

Preview width

Installation

Sign in to get your install command
Free with an account. It carries your token, so the CLI installs everything in one go.

Usage

import { SplittingText } from "@/components/ui/splitting-text";
<h1>
  <SplittingText text="Every letter finds its place" />
</h1>

Demos

Sequence

A headline by characters, then its subtitle by words: by="words" slides in each word whole, and delay (900 ms here) holds the subtitle back until the headline has landed. direction="bottom" raises the words from below.

Preview width

Lines

by="lines" slides in each line of the text, split at its line breaks (\n), 300 ms apart by default. Here direction="start" brings them in from the start of the line.

Preview width

Direction

direction is where each piece comes from: end, the default, is the end of the line; then start, top and bottom. Start and end follow the text's own direction, so in Arabic or Hebrew end is the left.

Preview width

Accessibility

Screen readers read the whole text once, as plain text: the moving pieces are hidden from them, and a visually hidden copy carries it. Words wrap whole, never between two of their characters, and the line keeps its direction on a right-to-left page. With reduced motion everything is in place from the start.

FAQ

Should I split by characters, words or lines?

Characters for a short headline, the most motion; words for a sentence, which stays readable while it arrives; lines for a few short lines, such as three steps. Splitting between characters breaks the joins of Arabic and other connected scripts: split those by words.

How long does it take?

duration is one piece's slide, 700 ms by default, and stagger the time between one piece and the next: 50 ms for characters, 200 for words, 300 for lines. The whole text takes the delay, a stagger per piece after the first, and one duration.

Can the pieces come from further away, or start blurred?

Yes, from your CSS: --splitting-text-distance is how far each piece slides (1.5em), and --splitting-text-filter a filter it starts from and loses as it lands, such as blur(8px). Set them on the text or any element around it.

When does the animation play?

With trigger="mount", the default, as soon as the page shows it: the animation runs from CSS alone, before the page's script loads. With trigger="view" it waits until a quarter of the text has scrolled into view, then plays once.

How do I run something after it finishes?

Pass onComplete: it's called once, when the last piece is in place, so you can show the next line or a button after it.

What happens with reduced motion?

Nothing slides: the text is there from the start, fully readable.

API Reference

SplittingText

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

PropType
textstring

The text. Its line breaks (\n) are kept.

by?"characters" | "words" | "lines"

What slides in on its own: each character, each word, or each line (the text's line breaks, \n).

Type
"characters" | "words" | "lines"
Default
"characters"
delay?number

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

direction?"end" | "start" | "top" | "bottom"

Where each one slides in from: the end of the line (the right, in a left-to-right text), its start, above or below.

Type
"end" | "start" | "top" | "bottom"
Default
"end"
duration?number

How long one character, word or line takes to slide in, in milliseconds.

Default
700
onComplete?() → void

Called once the last character, word or line is in place.

Returns
void
stagger?number

The time between one and the next, in milliseconds.

Default
50 (characters), 200 (words), 300 (lines)
trigger?"mount" | "view"

When it plays: as soon as it's on the page, or once it scrolls into view.

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-last?string
data-view?string

"in" when visible is true, otherwise "out".

CSS variableType
--splitting-text-distancestring

How far each unit slides in from (1.5em).

--splitting-text-durationstring

One unit's slide.

--splitting-text-filterstring

A filter each unit starts from, cleared as it lands (none; blur(8px) for a soft start).

All 97 text effects