Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Text

Pro

Rolling Text for React

Text whose characters roll over one after another, like the faces of a turning drum. For React with Base UI, when a label or a link should turn over with a mechanical click.

Framework

Rolling Text turns each character over in place: its face rolls up and away while the same character rolls in from below, in perspective, one character after the next, so a wave of rolls runs along the line. It plays once when the page shows it, once when it scrolls into view, or every time the pointer comes over it.

Use it for a short label with a mechanical feel: a departures board, a status, a navigation link that rolls on hover. For words that take turns, use Flip Words; for numbers that roll to a new value, Sliding Number. Each character is the front face of a small cube turning on an axis behind the text, moved by two CSS keyframe animations the install adds to your stylesheet, delayed by the character's place in the line, with no animation library. With reduced motion the text stands still.

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 { RollingText } from "@/components/ui/rolling-text";
<h2>
  <RollingText text="Now boarding" />
</h2>

Demos

Hover

trigger="hover" rolls the text every time the pointer comes over it, and when the link or button around it gets keyboard focus, so a navigation link answers both. On a touch screen it simply shows the text.

Preview width

Direction

direction is which way the characters turn: up, the default, rolls each face up and away with the next one coming from below; down rolls them the other way.

Preview width

Timing

duration is how long one character takes to roll over, 600 ms by default, and stagger the time between one character and the next, 50 ms. A short pair suits a small label; a long one makes a slow wave across a title. trigger="view" waits until the text scrolls into view.

Preview width

Accessibility

Screen readers read the text once, as plain text, from a visually hidden copy: the rolling characters are hidden from them. Words wrap whole, and the line keeps its direction on a right-to-left page. With reduced motion nothing rolls, on any trigger.

FAQ

How does the roll work?

Each character has two faces: the one you see, and a copy turned a quarter turn below it. Both turn together about an axis half a line behind the text, like a cube, so the face you see rolls up and away as the copy rolls in. The parent's perspective gives it depth.

Can it play again?

With trigger="hover", on every hover. With the other triggers it plays once; give it a new key and React renders it fresh, so it plays again from the start.

Can it roll to a different word?

No: each character rolls back to itself, for the motion. To change the words, use Flip Words or Rotating Text.

Which font suits it?

Any. The faces roll half a line above and below the text while they turn, so leave some line height around it in a dense block. A monospaced or uppercase label reads most like a departures board.

What happens with reduced motion?

The characters don't roll: the text is there, still, whatever the trigger.

API Reference

RollingText

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

PropType
textstring

The text.

direction?"up" | "down"

Which way each character rolls: its face turns up and away, or down. @default "up".

Type
"up" | "down"
Default
"up"
duration?number

How long one character takes to roll over, in milliseconds. @default 600.

stagger?number

The time between one character rolling and the next, in milliseconds. @default 50.

trigger?"mount" | "view" | "hover"

What rolls it: the page showing it, the text scrolling into view, or the pointer over it (again on every hover, and on keyboard focus of the link or button around it).

Type
"mount" | "view" | "hover"
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-view?string

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

CSS variableType
--rolling-text-durationstring

One character's roll (600ms).

--rolling-text-staggerstring

The time between one character rolling and the next (50ms).

--rolling-text-turnstring
All 97 text effects