Installation
Usage
import AutoScrollingClientCarousel from "@/components/ruixen/auto-scrolling-client-carousel";
// Text-based logos (default)
<AutoScrollingClientCarousel />;
// With custom logo elements
const clients = [
{
name: "GitHub",
logo: <img src="/github.svg" alt="" className="h-6 w-auto" />,
},
{
name: "Vercel",
logo: <img src="/vercel.svg" alt="" className="h-5 w-auto" />,
},
{ name: "Linear" },
{ name: "Stripe" },
];
<AutoScrollingClientCarousel
clients={clients}
title="Backed by the best"
speed={25}
/>;Props
| Prop | Type | Default | Description |
|---|---|---|---|
title | string | "Trusted by leading teams" | Heading text above the ribbons |
clients | AutoScrollingCarouselItem[] | 8 default company names | Array of client items |
speed | number | 35 | Seconds per full scroll cycle |
className | string | - | Additional CSS classes |
AutoScrollingCarouselItem
| Property | Type | Description |
|---|---|---|
name | string | Client name (rendered as text if no logo provided) |
logo | React.ReactNode | Optional custom logo element (SVG, img, component) |
href | string | Optional link URL |
Features
- Dual Ribbon: Two rows scrolling in opposite directions — row 1 left, row 2 right. The second row uses the client array reversed so logos never align vertically
- Speed Polyrhythm: Row 2 runs at 1.15x the speed of row 1. The slight offset creates a phasing rhythm — logos drift in and out of vertical alignment over time
- Grayscale Bloom: No opacity dimming — logos are always at full opacity. The "muted" state uses
filter: grayscale(1)(monochrome). On hover, color blooms back withgrayscale(0)via a smooth 400ms ease. Colored logos get a satisfying desaturation-to-color reveal - Spring Scale Lift: Hovered logos scale to
1.06withtranslateY(-2px)usingcubic-bezier(0.34, 1.56, 0.64, 1)— a spring with slight overshoot, distinct from the other showcases' curves - Always Moving: Unlike client-carousel-showcase (which pauses on hover), these ribbons never stop. The interaction is purely visual — grayscale and scale, not motion control
- Gradient Edge Masks: Both rows fade to transparent at the 8% and 92% marks via
mask-image - Text-Based Defaults: Default clients render as clean semibold text — pass custom
logoReactNodes for real brand logos - Zero Dependencies: No embla-carousel, no framer-motion, no next/image — pure CSS animation with inline keyframes
- Accessibility: Semantic section,
aria-labelon linked logos, keyboard-focusable

