✨ MCP support is now available in Sora UI.
Sora UI

Text Roll

A per-character vertical text roll animation for label swaps and micro-interactions.

Made by Axyl

Installation

Usage

TextRoll does not animate on hover or click by itself — update the text prop (same as SlotText from slot-text):

import { useState } from 'react';
import { TextRoll } from '@/components/sora-ui/texts/text-roll';

export default function CopyButton() {
  const [copied, setCopied] = useState(false);

  return (
    <button
      type="button"
      onClick={() => {
        setCopied(true);
        window.setTimeout(() => setCopied(false), 1400);
      }}
    >
      <TextRoll text={copied ? 'Copied' : 'Copy'} />
    </button>
  );
}

Click the preview button to see Copy → Copied roll. Hover alone does not trigger the effect.

Direction, stagger, and bounce:

<TextRoll
  text={label}
  direction="up"
  stagger={60}
  bounce={0.8}
  className="font-mono text-sm font-semibold"
/>

Chromatic sweep on roll — pass a color function or use the built-in helper:

import { TextRoll, chromatic } from '@/components/sora-ui/texts/text-roll';

<TextRoll
  text={label}
  options={{
    direction: 'up',
    skipUnchanged: false,
    color: chromatic({ from: 190 }),
  }}
/>;

For aligned short labels (CopyCopied), keep skipUnchanged at the default true so shared letters stay put. Turn it off when lengths differ so the whole line rolls uniformly.

Props

PropTypeDefault
text?
string
-
options?
TextRollOptions
-
direction?
"up" | "down"
"down"
stagger?
number
45
duration?
number
300
bounce?
number
0.6
skipUnchanged?
boolean
true
chromatic?
boolean
false
className?
string
-

Credits

Inspired by slot-text.

Built by Axyl. The source code will be available on GitHub soon.

Last updated: 6/19/2026