Skip to main content

Search rules

Search all UI Guides rules by name, category, or source

animationsanimate-text

Overlap a Text Swap; Never Hard-Cut the Slot

MUST

MUST: Rotating/replaced text must overlap its exit and enter (100–300ms, or at minimum a 28–85ms micro-delay) so no frame shows an empty slot, and both layers must share one grid cell (grid-area: 1/1) sized to the longest string so surrounding content never reflows. A looping swap also needs a pause control and a reduced-motion path.

A rotating word must start entering before the old one has finished leaving, in a slot sized so the line around it never moves

// bad — hard cut, slot resizes every tick
setInterval(() => setI(i => (i + 1) % words.length), 2000)
// good — stacked layers, enter starts before exit ends
<span style={{ display: "inline-grid" }}>
  {words.map((w, i) => (
    <span key={w} style={{ gridArea: "1 / 1" }} className={i === index ? "enter" : i === leaving ? "exit" : "invisible"}>{w}</span>
  ))}
</span>

Bad

Good

Why it matters

The "Build ___ faster" rotating headline is usually a `setInterval` that swaps a string, and it fails twice on the same frame. First the cut: with no overlap there is a moment where the old word is gone and the new one has not arrived, and an empty slot reads as a bug, not a transition. The catalog overlaps 100–300ms on crossfade effects (soft-blur-in 300, mask-reveal-up 210, per-word-crossfade 170) and — this is the part that gets skipped — even the effects with `overlap_ms: 0` still insert a `micro_delay_ms` of 28–85ms rather than cutting at exactly t=0, because the beat is what makes a replacement read as choreography instead of a glitch.

Second the reflow: mount both layers in normal flow during the overlap and the line doubles in height, then snaps back. Stack them in one grid cell instead — a `grid` container with both children on `grid-area: 1 / 1` — which also sizes the slot to the WIDEST string automatically, so the words on either side stop shuffling every four seconds. Reserving that width is the same argument as performance-no-image-cls, one text node down.

And a swap that loops is looping text: content-moving-text-can-be-paused still applies, so it needs a reduced-motion path and a way to stop it.

Built by Gleb Stroganov, design engineer at Evil Martians.

The rules come from other people's skills and guidelines — Vercel, Rauno Freiberg, @Ibelick, impeccable, Emil Kowalski, Tailwind, RAMS — each one credited on the Sources page. The work here is extraction and wiring: every rule is pulled into one corpus, given a good and a bad example you can operate, a MUST/SHOULD/NEVER rule an agent can paste, and a link back to where it came from.