Small details make the whole thing feel alive.
Customize
Usage
import { WordRise } from "@/components/motionkit/word-rise";
<WordRise
as="h2"
text="Small details make the whole thing feel alive."
className="text-4xl font-semibold"
/>Motion
The exact curves this component runs, plotted with Motion's own maths.
Each word
Scrolls into view
Works in the App Router as is. Requires Tailwind CSS v4.
npm install motionSave as components/motionkit/word-rise.tsx.
"use client";
import type { ElementType } from "react";
import { motion, useReducedMotion } from "motion/react";
type WordRiseProps = {
text: string;
/** Seconds between each word starting. */
stagger?: number;
/** Seconds each word takes to settle. */
duration?: number;
/** Play only the first time it scrolls into view. */
once?: boolean;
/** Wrapping element, e.g. "h1". */
as?: ElementType;
className?: string;
};
export function WordRise({ text, stagger = 0.08, duration = 0.6, once = true, as: Tag = "p", className = "" }: WordRiseProps) {
const reduceMotion = useReducedMotion();
const words = text.split(" ");
return (
<Tag className={className}>
{/* screen readers get the sentence once; the animated words are hidden from them */}
<span className="sr-only">{text}</span>
<motion.span
aria-hidden
initial="hidden"
whileInView="visible"
viewport={{ once, amount: 0.6 }}
variants={{ hidden: {}, visible: { transition: { staggerChildren: stagger } } }}
>
{words.map((word, index) => (
<motion.span
key={`${word}-${index}`}
className="inline-block whitespace-pre"
variants={{
// reduced motion: words are simply there, nothing rises
hidden: reduceMotion ? { opacity: 1 } : { opacity: 0, y: "0.5em", filter: "blur(8px)" },
visible: { opacity: 1, y: 0, filter: "blur(0px)", transition: { duration, ease: [0.22, 1, 0.36, 1] } },
}}
>
{word}
{index < words.length - 1 ? " " : ""}
</motion.span>
))}
</motion.span>
</Tag>
);
}
| Prop | Type | Default | Description |
|---|---|---|---|
| text | string | — | The sentence to reveal. |
| stagger | number | 0.08 | Seconds between each word starting. |
| duration | number | 0.6 | Seconds each word takes to settle. |
| once | boolean | true | Play only the first time it scrolls into view. |
| as | ElementType | "p" | Wrapping element, e.g. "h1". |
Make every word land.
Kinetic Headline
Headlines that arrive word by word or letter by letter: slide, blur, hinge or rise from behind a mask, from any direction.
Monthly revenue
Number Ticker
Counts up to a value with an eased finish when it scrolls into view.
Small details, big impact.
Kinetic Text
Headlines that rise letter by letter, slide up line by line, blur into focus or light up as you scroll.