PParable
All components

Testimonial Marquee

Blocks & Slices

A wall of testimonial rows scrolling infinitely in alternating directions via a seamless two-half translateX(-50%) loop; hovering a row or tabbing onto any card pauses just that row, short rows are tiled with aria-hidden passes so the track always outruns the viewport, and cards fall back to a brand-accent initials disc when no avatar is given. Under prefers-reduced-motion it collapses to a static wrapped grid with no scroll and no duplicates.

Inspired by Cult Pro — testimonial walls (pattern) — independently built, not affiliated. Attribution policy

  • We swapped three tools for this and shipped a week early.
    Mara EllisonCTO, Fieldnote
  • Installed one component, kept the whole registry.
    Priya RaghavanFounder, Statlight
  • It reads like code we wish we had written ourselves.
    Alma ReyesStaff engineer, Driftwood
  • The polish out of the box is unreal. Our landing page finally feels alive.
    Devon OkaforDesign lead, Loomline
  • Accessibility handled by default. Our audit came back spotless.
    Jonas WeberEngineering, Kupfer
  • Marketing pages went from weeks to an afternoon.
    Theo LindqvistProduct, Norrsken

Installation

npx shadcn@latest add https://parable-three.vercel.app/r/testimonial-marquee.json

Runs the shadcn CLI — the component source is copied intocomponents/parable/testimonial-marquee.tsx. You own it from there.

Usage

The exact code rendering the preview above.

<div className="w-full max-w-3xl py-2">
    <TestimonialMarquee
      rows={2}
      speed={26}
      testimonials={[
        { quote: "We swapped three tools for this and shipped a week early.", name: "Mara Ellison", role: "CTO, Fieldnote" },
        { quote: "The polish out of the box is unreal. Our landing page finally feels alive.", name: "Devon Okafor", role: "Design lead, Loomline" },
        { quote: "Installed one component, kept the whole registry.", name: "Priya Raghavan", role: "Founder, Statlight" },
        { quote: "Accessibility handled by default. Our audit came back spotless.", name: "Jonas Weber", role: "Engineering, Kupfer" },
        { quote: "It reads like code we wish we had written ourselves.", name: "Alma Reyes", role: "Staff engineer, Driftwood" },
        { quote: "Marketing pages went from weeks to an afternoon.", name: "Theo Lindqvist", role: "Product, Norrsken" },
      ]}
    />
  </div>

Props

TestimonialMarqueeProps extends React.HTMLAttributes<HTMLElement>

PropTypeDefaultDescription
testimonials*Testimonial[]The testimonials, distributed round-robin across the rows.
rowsnumber2How many scrolling rows to render (clamped to the testimonial count).
speednumber40Seconds one full loop takes. Lower is faster.