Horizontal sliding is the default testimonial animation and the wrong one: text that moves sideways while you're reading it is text you restart. A crossfade swaps quotes in place — the eye stays anchored where the next quote appears. For a single-slot rotator, fade beats slide every time.
Velocity X's quote-crossfade-carousel is the pattern plus the two details that make it production-grade instead of a CodePen.
The Money Pattern
Every quote occupies the same grid cell; only opacity changes. Grid stacking (not absolute positioning) is what makes the height correct for free:
<div class="grid">
{quotes.map((q, i) => (
<figure
class={`col-start-1 row-start-1 transition-opacity duration-700
${i === active ? 'opacity-100' : 'opacity-0 pointer-events-none'}`}
aria-hidden={i !== active}
>
<blockquote class="text-2xl">{q.text}</blockquote>
<figcaption class="mt-4 text-sm">{q.name} — {q.role}</figcaption>
</figure>
))}
</div>
Because every figure sits in col-start-1 row-start-1, the grid row is as tall as the tallest quote — the container never resizes between quotes, so the content below never jumps. That's the layout-shift bug absolute positioning + measured heights usually reintroduces, solved by the display mode itself.
The Catch
pointer-events-none on the hidden quotes is load-bearing: they're still in the layout, stacked under the visible one, and without it an invisible link in quote three eats clicks meant for quote one. Pair it with aria-hidden so assistive tech reads exactly one quote.
Timing discipline is the same as every rotator: ~7 seconds per quote minimum (people read slower than designers skim), pause on hover and focus, stop on reduced motion, and dots or arrows if there are more than three quotes — past that, rotation without controls is a slot machine.
The Verdict
Grid-stack, opacity fade, tallest-quote height, pointer-events discipline. In-place rotation that never fights the reader or shifts the page. It's in Velocity X's Carousels & Tickers — and if you only have three good quotes, the honest answer is still the static grid.









