All components
Marquee
effectsAn infinite, seamless marquee with hover-pause and vertical support.
responsive · 320px
Install
Same command in any shadcn project — React (Vite/CRA), Next.js, Remix, Astro, and more:
$
npx shadcn@latest add https://your-domain/r/marquee.jsonUsage
import { Marquee } from "@/registry/effects/marquee";
const items = ["Next.js", "TypeScript", "Tailwind", "shadcn/ui", "Radix", "Motion"];
export default function MarqueeDemo() {
return (
<div className="relative w-full max-w-md overflow-hidden">
<Marquee pauseOnHover className="[--duration:18s]">
{items.map((item) => (
<span key={item} className="rounded-full border border-border bg-card px-4 py-1.5 text-sm font-medium text-card-foreground">
{item}
</span>
))}
</Marquee>
<div className="pointer-events-none absolute inset-y-0 left-0 w-12 bg-gradient-to-r from-background" />
<div className="pointer-events-none absolute inset-y-0 right-0 w-12 bg-gradient-to-l from-background" />
</div>
);
}Component source
"use client";
import * as React from "react";
import { cn } from "@/lib/utils";
export interface MarqueeProps extends React.ComponentPropsWithoutRef<"div"> {
/** Scroll vertically instead of horizontally. */
vertical?: boolean;
/** Reverse the scroll direction. */
reverse?: boolean;
/** Pause the animation on hover. */
pauseOnHover?: boolean;
/** Number of times to repeat the children for a seamless loop. */
repeat?: number;
}
/**
* An infinite, seamless marquee. Wrap any set of children; they scroll
* forever. Set `--duration` and `--gap` via style to tune speed/spacing.
*/
export const Marquee = React.forwardRef<HTMLDivElement, MarqueeProps>(
(
{
className,
vertical = false,
reverse = false,
pauseOnHover = false,
repeat = 4,
children,
style,
...props
},
ref,
) => {
return (
<div
ref={ref}
style={
{
"--duration": "40s",
"--gap": "1rem",
...style,
} as React.CSSProperties
}
className={cn(
"group flex overflow-hidden p-2 [gap:var(--gap)]",
vertical ? "flex-col" : "flex-row",
className,
)}
{...props}
>
{Array.from({ length: repeat }).map((_, i) => (
<div
key={i}
className={cn("flex shrink-0 justify-around [gap:var(--gap)]", {
"animate-marquee flex-row": !vertical,
"animate-marquee-vertical flex-col": vertical,
"group-hover:[animation-play-state:paused]": pauseOnHover,
"[animation-direction:reverse]": reverse,
})}
>
{children}
</div>
))}
</div>
);
},
);
Marquee.displayName = "Marquee";