Build faster, smarter, together
Customize
Usage
import { MorphingText } from "@/components/motionkit/morphing-text";
<h1>
Build <MorphingText words={["faster", "smarter", "together"]} />
</h1>Motion
The exact curves this component runs, plotted with Motion's own maths.
Each letter
New word every 2.4s
Works in the App Router as is. Requires Tailwind CSS v4.
npm install motionSave as components/motionkit/morphing-text.tsx.
"use client";
import { useEffect, useState } from "react";
import { AnimatePresence, motion, useReducedMotion } from "motion/react";
type MorphingTextProps = {
words: string[];
/** Seconds each word stays before the next arrives. */
interval?: number;
/** Seconds between letters as a word arrives. */
stagger?: number;
className?: string;
};
export function MorphingText({ words, interval = 2.4, stagger = 0.03, className = "" }: MorphingTextProps) {
const reduceMotion = useReducedMotion();
const [index, setIndex] = useState(0);
useEffect(() => {
// rotating text never starts for reduced-motion users: they see the first word
if (reduceMotion || words.length < 2) return;
const timer = window.setInterval(() => setIndex((current) => (current + 1) % words.length), interval * 1000);
return () => window.clearInterval(timer);
}, [reduceMotion, words.length, interval]);
const word = words[reduceMotion ? 0 : index % words.length] ?? "";
return (
<span className={`relative inline-flex ${className}`}>
<span className="sr-only">{words.join(", ")}</span>
<AnimatePresence mode="popLayout" initial={false}>
<motion.span key={word} aria-hidden className="inline-flex whitespace-pre">
{word.split("").map((letter, letterIndex) => (
<motion.span
key={letterIndex}
className="inline-block"
initial={{ opacity: 0, y: "0.4em", filter: "blur(6px)" }}
animate={{ opacity: 1, y: 0, filter: "blur(0px)" }}
exit={{ opacity: 0, y: "-0.4em", filter: "blur(6px)", transition: { duration: 0.2, delay: letterIndex * stagger * 0.5 } }}
transition={{ duration: 0.35, delay: letterIndex * stagger, ease: [0.22, 1, 0.36, 1] }}
>
{letter}
</motion.span>
))}
</motion.span>
</AnimatePresence>
</span>
);
}
| Prop | Type | Default | Description |
|---|---|---|---|
| words | string[] | — | Words to rotate through. |
| interval | number | 2.4 | Seconds each word stays. |
| stagger | number | 0.03 | Seconds between letters as a word arrives. |
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.
Liquid light
Liquid Gradient Text
Pools of colour swirl and flow inside the letters, for headings that feel alive without moving an inch.
Think beyond ordinary.
Gradient Text
Headline text with a slowly flowing, seamlessly looping gradient.