WebberUI

Velocity Marquee

An infinitely looping marquee that speeds up with scroll velocity and briefly reverses when you scroll back quickly.

Loading preview…
npx shadcn@latest add https://webberui.com/r/velocity-marquee.json

Playground

Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.

5
<VelocityMarquee />

Installation

npx shadcn@latest add https://webberui.com/r/velocity-marquee.json

Usage

children can be anything. Remember to leave trailing spacing (such as pr-8 or a trailing separator) so the loop is seamless:

import { VelocityMarquee } from "@/components/ui/velocity-marquee";

<VelocityMarquee baseVelocity={5}>
  <span className="pr-8 text-5xl font-bold">
    WebberUI — Animate everything ·
  </span>
</VelocityMarquee>

It also works for a logo row, with a negative baseVelocity to scroll the other way:

<VelocityMarquee baseVelocity={-3}>
  <div className="flex items-center gap-12 pr-12">
    <LogoA className="h-8" />
    <LogoB className="h-8" />
    <LogoC className="h-8" />
  </div>
</VelocityMarquee>

Props

PropTypeDefaultDescription
childrenReactNodeThe marquee content; four copies are rendered internally for a seamless loop
baseVelocitynumber5Base speed (percent of the content width moved per second); negative reverses
direction"left" | "right""left"Travel direction; "right" is equivalent to negating baseVelocity
classNamestringApplied to the outer container

How it works

  • Scroll-driven speed: useScroll().scrollYuseVelocity gives the scroll speed (px/s) → useSpring smooths it → it is mapped to a speed multiplier, and useAnimationFrame accumulates the offset frame by frame. The faster the page scrolls, the faster the marquee runs; once scrolling stops, the spring eases it back to the base speed
  • Scrolling back quickly makes the speed multiplier negative, so the marquee briefly reverses direction before recovering
  • The offset wraps between -25% and 0% through a hand-written wrap function, with four copies of the content rendered so it is always visually seamless. A single copy should be at least a third of the container width to avoid exposing blank space
  • The animation only touches transform and never triggers layout; copies 2 through 4 are marked aria-hidden, so the screen reader only reads one
  • When the user has "reduce motion" enabled at the system level, it degrades to a single static copy that does not scroll

On this page