All components

Velocity Marquee

Marketing

An infinite strip whose speed and skew couple to scroll velocity — it accelerates as you scroll, reverses when you scroll back, and eases to a base drift when you stop. The wrap is a modulo on a measured content width (seamless in both directions, no CSS-animation restart), and the velocity is smoothed by an exponential moving average so it coasts instead of snapping.

motion valuesseamless wrapscroll velocityexponential decayzero re-renders

Scroll me — fast, slow, and backwards

01 Flick down and the strip accelerates left and shears with it. Flick up hard enough and it crosses zero and runs the other way. Let go and it coasts back to the base drift instead of stopping dead — that easing is the whole point.

02 Flick down and the strip accelerates left and shears with it. Flick up hard enough and it crosses zero and runs the other way. Let go and it coasts back to the base drift instead of stopping dead — that easing is the whole point.

03 Flick down and the strip accelerates left and shears with it. Flick up hard enough and it crosses zero and runs the other way. Let go and it coasts back to the base drift instead of stopping dead — that easing is the whole point.

04 Flick down and the strip accelerates left and shears with it. Flick up hard enough and it crosses zero and runs the other way. Let go and it coasts back to the base drift instead of stopping dead — that easing is the whole point.

05 Flick down and the strip accelerates left and shears with it. Flick up hard enough and it crosses zero and runs the other way. Let go and it coasts back to the base drift instead of stopping dead — that easing is the whole point.

06 Flick down and the strip accelerates left and shears with it. Flick up hard enough and it crosses zero and runs the other way. Let go and it coasts back to the base drift instead of stopping dead — that easing is the whole point.

07 Flick down and the strip accelerates left and shears with it. Flick up hard enough and it crosses zero and runs the other way. Let go and it coasts back to the base drift instead of stopping dead — that easing is the whole point.

08 Flick down and the strip accelerates left and shears with it. Flick up hard enough and it crosses zero and runs the other way. Let go and it coasts back to the base drift instead of stopping dead — that easing is the whole point.

09 Flick down and the strip accelerates left and shears with it. Flick up hard enough and it crosses zero and runs the other way. Let go and it coasts back to the base drift instead of stopping dead — that easing is the whole point.

10 Flick down and the strip accelerates left and shears with it. Flick up hard enough and it crosses zero and runs the other way. Let go and it coasts back to the base drift instead of stopping dead — that easing is the whole point.

11 Flick down and the strip accelerates left and shears with it. Flick up hard enough and it crosses zero and runs the other way. Let go and it coasts back to the base drift instead of stopping dead — that easing is the whole point.

12 Flick down and the strip accelerates left and shears with it. Flick up hard enough and it crosses zero and runs the other way. Let go and it coasts back to the base drift instead of stopping dead — that easing is the whole point.

13 Flick down and the strip accelerates left and shears with it. Flick up hard enough and it crosses zero and runs the other way. Let go and it coasts back to the base drift instead of stopping dead — that easing is the whole point.

14 Flick down and the strip accelerates left and shears with it. Flick up hard enough and it crosses zero and runs the other way. Let go and it coasts back to the base drift instead of stopping dead — that easing is the whole point.

Decay · 0.35s
Coupling · 1.2
Skew · 6°
Playback

Drop decay to 0.05s and the strip snaps to a halt the instant you stop — that is exactly the broken-feeling version. 0.35s is the default.

Installation

Terminal
npx shadcn@latest add https://ui.saumyarex.xyz/r/velocity-marquee.json

Props

PropTypeDefaultDescription
childrenReact.ReactNodeOne copy of the strip's content. It is duplicated at runtime until it covers the container — the count is derived from a measured width, never hardcoded. Only the first copy is in the accessibility tree; the rest are `aria-hidden` and `inert`.
baseVelocitynumber40Resting drift in px/s. Positive drifts left, negative drifts right.
velocityFactornumber1.2How strongly scroll velocity adds to the drift. Set to 0 for a plain constant marquee.
decaynumber0.35Time constant of the exponential decay, in seconds — how long the strip coasts after you stop scrolling. This is the feel of the component: at 0.05 it snaps to a halt and reads as broken.
maxSkewnumber6Peak skew in degrees, reached at ±1400 px/s of scroll. The copy count compensates for the horizontal shear, so raising this never exposes a seam. 0 disables it.
scrollRefReact.RefObject<HTMLElement | null>Element whose `scrollTop` drives the effect. Defaults to the window.
pausedbooleanfalseFreeze the strip in place. Surface it as a control to satisfy WCAG 2.2.2; `prefers-reduced-motion` already stops it entirely.

Dependencies

motionclsxtailwind-merge