shadcn.io is not affiliated with official shadcn/ui
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.
Installation
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.
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.
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.
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.
API Reference
SplittingText
<span> data-slot="splitting-text"
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.
data-last?stringdata-view?string
"in" when visible is true, otherwise "out".
--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).
Related
Blur Text
EntranceWords that come into focus from a blur
- Pro
Writing Text
EntranceWords at the pace of speech
- Pro
Paper Fold Text
EntranceLetters that unfold from the middle
- Pro
Pop Text
EntranceLetters that spring in with a burst
- Pro
Stamp Text
EntranceLetters pressed on with a lean
- Pro
Mask Reveal Text
EntranceThe whole line in one wipe