Skip to content

Rotating Word Swap Headline

A headline where one word auto-cycles with a vertical odometer-style swap.

Freeeditorialplayful
Category
Text Effects
Added
2026-08-22
Deps
1
Updated
2026-09-01
Preview

Make itfast

Props

1800
Requires framer-motion
"use client";

import { useEffect, useState } from "react";
import { AnimatePresence, motion } from "framer-motion";

export function RotatingWordSwap({
  prefix = "Make it",
  words = ["fast", "clean", "vibed", "shipped"],
  interval = 1800,
}: {
  prefix?: string;
  words?: string[];
  interval?: number;
}) {
  const [index, setIndex] = useState(0);

  useEffect(() => {
    const id = setInterval(() => setIndex((i) => (i + 1) % words.length), interval);
    return () => clearInterval(id);
  }, [words.length, interval]);

  const widest = words.reduce((a, b) => (b.length > a.length ? b : a), "");

  return (
    <p className="flex items-center gap-2 text-3xl font-black">
      {prefix}
      <span className="relative inline-block h-[1.1em] overflow-hidden align-bottom">
        {/* Invisible widest word reserves the box width so the line doesn't reflow on every swap. */}
        <span aria-hidden className="invisible whitespace-nowrap">
          {widest}
        </span>
        <AnimatePresence mode="popLayout">
          <motion.span
            key={words[index]}
            initial={{ y: "100%", opacity: 0 }}
            animate={{ y: "0%", opacity: 1 }}
            exit={{ y: "-100%", opacity: 0 }}
            transition={{ duration: 0.4, ease: [0.65, 0, 0.35, 1] }}
            className="absolute left-0 top-0 inline-block whitespace-nowrap text-red-500"
          >
            {words[index]}
          </motion.span>
        </AnimatePresence>
      </span>
    </p>
  );
}
Notes

About this text effect

A headline where one word cycles through a list needs the surrounding text to stay put while the word changes size. Clean and shipped are not the same width, and if the layout reflows on every swap the whole line visibly jumps every couple of seconds. The fix is a spacer: an invisible, normally flowed span holding the widest word in the list reserves the box's real width and height, while the actual animated word sits absolutely positioned on top of it inside a relatively positioned, overflow-hidden wrapper. Skip the absolute positioning and the animated word sits as a plain sibling next to the invisible spacer instead of stacked over it, which breaks the layout the moment the spacer is added at all, an easy first-draft mistake. AnimatePresence in popLayout mode, keyed on the word text itself, drives the vertical slide-up-and-out and slide-up-and-in swap on a setInterval loop cleaned up in useEffect. Compare this against a plain fade if the odometer-style motion is not needed; the interval runs unconditionally, with no pause-on-hover and no stop control.

Curator’s note

The animated word has to be absolutely positioned over a separate invisible spacer holding the widest word — an easy first-draft mistake is leaving the animated word as a normal inline sibling next to that spacer, which sits them side by side instead of stacked, breaking the layout the moment the spacer is added.

Related

Pairs well with

Matched on shared tags and category — the entries most likely to be used alongside this one.

Typewriter Text

text effects

Text that types itself out character by character, then cycles to the next phrase.

typewritertextcycle
Featured
New

Slice Shear Hover

text effects

Display type cut into horizontal bands that fan apart under the pointer.

hovertextclip-path
Featured
New

Weight Wave Text

text effects

Per-character variable font weight that swells around the pointer and drifts when idle.

textvariable-fonthover