Rolling Letters
Displays a word where each character animates with a vertical rolling effect, creating a dynamic text reveal.
1. Copy the component file
Create a new file called rolling-letters-animation.jsx in
your reusable components folder (for example
/src/components/) and paste the following code
into it.
rolling-letters-animation.jsx
import { memo, useMemo } from "react";
import styles from "./rolling-letters-animation.module.css";
const RollingLettersAnimation = (props) => {
const {
word,
letterBlockSize = 16,
duration = 2000,
className,
style,
letterClassName,
letterStyle,
...restProps
} = props;
const _duration = Math.max(100, duration);
const upperCaseLetterSet = useMemo(() => (
Array.from({
length: 26,
}).map((_, i) => (
String.fromCharCode(65 + i)
))
), []);
const lowerCaseLetterSet = useMemo(() => (
Array.from({
length: 26,
}).map((_, i) => (
String.fromCharCode(97 + i)
))
), []);
const getRandomSeries = (exceptLetter) => {
const isUpperCase = exceptLetter === exceptLetter.toUpperCase();
const letterSet = isUpperCase ? upperCaseLetterSet : lowerCaseLetterSet;
const lettersExceptGivenLetter = letterSet.filter(l => l !== exceptLetter);
const shuffledLetterSet = lettersExceptGivenLetter.sort(() => Math.random() - Math.random());
return shuffledLetterSet;
};
return (
<span
{...restProps}
className={[
className,
styles["rolling-letters-animation"],
].join(" ")}
style={{
...style,
"--animation-duration": `${_duration}ms`,
"--letter-block-size": `${letterBlockSize}px`,
}}
>
{[...word].map((letter, letterIndex) => {
const series = getRandomSeries(letter);
const isReverse = (letterIndex % 2) === 0;
if (isReverse) {
series.unshift(letter);
} else {
series.push(letter);
}
return (
<span
aria-hidden={true}
key={`letter-column-${letter}-${letterIndex}`}
className={styles["letters-wrapper"]}
style={{
"--total-rolling-letters": `${series.length - 1}`,
}}
>
{series.map((l, i) => (
<span
aria-hidden={true}
key={`letter-block-${l}-${i}`}
className={[
letterClassName,
styles["letter"],
].join(" ")}
style={letterStyle}
>
{l}
</span>
))}
</span>
)
})}
<span
className={styles["sr-only"]}
>
{word}
</span>
</span>
);
};
export default memo(RollingLettersAnimation); 2. Copy the CSS module file
In the same folder, create a file called rolling-letters-animation.module.css and paste the following CSS.
rolling-letters-animation.module.css
.rolling-letters-animation {
position: relative;
display: inline-block;
height: var(--letter-block-size);
>.letters-wrapper {
display: inline-block;
width: var(--letter-block-size);
height: var(--letter-block-size);
overflow: hidden;
>.letter {
display: grid;
place-items: center;
width: var(--letter-block-size);
height: var(--letter-block-size);
overflow: hidden;
&:first-child {
animation: rolling-letters-keyframes var(--animation-duration) cubic-bezier(0, 0.34, 0.1, 1.11) forwards;
}
}
&:nth-child(odd) {
>.letter {
&:first-child {
margin-top: calc(var(--total-rolling-letters) * var(--letter-block-size) * -1);
animation-name: rolling-letters-reverse-keyframes;
}
}
}
}
> .sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
animation: none;
}
}
@keyframes rolling-letters-keyframes {
from {
margin-top: 0%;
}
to {
margin-top: calc(var(--total-rolling-letters) * calc(var(--letter-block-size) * -1));
}
}
@keyframes rolling-letters-reverse-keyframes {
from {
margin-top: calc(var(--total-rolling-letters) * calc(var(--letter-block-size) * -1));
}
to {
margin-top: 0%;
}
} 3. Use the component
Now you can import and use the component anywhere in your project.
rolling-letters-animation-preview.jsx
import RollingLettersAnimation from "@/components/text-effects/rolling-letters-animation/rolling-letters-animation";
const RollingLettersAnimationPreview = () => {
return (
<RollingLettersAnimation
word="MosaicUI"
letterBlockSize={32}
style={{
fontFamily: "monospace",
fontSize: "32px",
fontWeight: "800",
}}
/>
);
};
export default RollingLettersAnimationPreview; Props
Configure the component with the following props:
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
| word | string | Yes | — | The text to display and animate with the rolling letter effect. |
| letterBlockSize | number | No | 16 | Size of the square block (width and height) used for each letter container. This helps maintain consistent spacing when fonts are not monospace. Typically set to match the text font-size. |
| duration | number | No | 2000 | Total animation duration in milliseconds. Minimum value: 100. |
| className | string | No | — | Additional CSS class applied to the root container element. |
| style | React.CSSProperties | No | — | Inline styles applied to the root container element. |
| letterClassName | string | No | — | CSS class applied to each individual letter element. Useful for custom letter styling or effects. |
| letterStyle | React.CSSProperties | No | — | Inline styles applied to each letter element. |