ComponentsText Animations
Infinite Ribbon
Continuous marquee-style scrolling ribbon for React. Pure CSS keyframes, zero dependencies, fully customizable speed, direction, rotation and repeat count. Perfect for hero banners, announcements and ticker effects.
Last updated on
"use client";
import { InfiniteRibbon } from "@/components/ui/infinite-ribbon";
export function InfiniteRibbonDemo() {
return (
<div className="relative w-full overflow-hidden rounded-md border bg-background">
<InfiniteRibbon>✦ JolyUI · Infinite Ribbon · Build beautiful interfaces ✦</InfiniteRibbon>
<div className="h-32" />
</div>
);
}Installation
CLI
npx shadcn@latest add "https://jolyui.dev/r/infinite-ribbon"Manual
Copy and paste the following code into your project component/ui/infinite-ribbon.tsx
import type * as React from "react";
import { cn } from "@/lib/utils";
export interface InfiniteRibbonProps {
repeat?: number;
duration?: number;
reverse?: boolean;
rotation?: number;
children: React.ReactNode;
className?: string;
}
const ribbonAnimationStyles = `
@keyframes iconiq-infinite-ribbon {
from {
transform: translateX(0);
}
to {
transform: translateX(-50%);
}
}
@keyframes iconiq-infinite-ribbon-reverse {
from {
transform: translateX(-50%);
}
to {
transform: translateX(0);
}
}
@media (prefers-reduced-motion: reduce) {
.iconiq-infinite-ribbon-track {
animation-duration: 1ms !important;
animation-iteration-count: 1 !important;
}
}
`;
export function InfiniteRibbon({
repeat = 5,
duration = 10,
reverse = false,
rotation = 0,
children,
className,
}: InfiniteRibbonProps) {
const repeatCount = Math.max(1, Math.floor(repeat));
const animationName = reverse
? "iconiq-infinite-ribbon-reverse"
: "iconiq-infinite-ribbon";
return (
<div
className={cn(
"w-full max-w-full overflow-hidden bg-yellow-400 py-1 text-black text-lg dark:bg-yellow-500 dark:text-black",
className
)}
style={{ transform: `rotate(${rotation}deg)` }}
>
<span className="sr-only">{children}</span>
<div
aria-hidden="true"
className="iconiq-infinite-ribbon-track flex w-max whitespace-nowrap"
style={
{
"--ribbon-duration": `${Math.max(0.1, duration)}s`,
animation: `${animationName} var(--ribbon-duration) linear infinite`,
} as React.CSSProperties
}
>
{Array.from({ length: repeatCount * 2 }, (_, index) => (
<span className="mr-8 inline-block select-none" key={index}>
{children}
</span>
))}
</div>
<style>{ribbonAnimationStyles}</style>
</div>
);
}Usage
import { InfiniteRibbon } from "@/components/ui/infinite-ribbon";
<InfiniteRibbon repeat={5} duration={12}>
✦ JolyUI · Infinite Ribbon · Build beautiful interfaces ✦
</InfiniteRibbon>Examples
Variants
"use client";
import { InfiniteRibbon } from "@/components/ui/infinite-ribbon";
export function InfiniteRibbonCustomDemo() {
return (
<div className="flex flex-col items-stretch justify-center gap-8">
<div className="space-y-2">
<p className="font-medium text-sm">Slow forward ribbon</p>
<InfiniteRibbon repeat={4} duration={20}>
🚀 Launch faster · Ship more · Sleep better 🚀
</InfiniteRibbon>
</div>
<div className="space-y-2">
<p className="font-medium text-sm">Fast reverse ribbon</p>
<InfiniteRibbon repeat={6} duration={6} reverse className="bg-pink-500 text-white dark:bg-pink-600">
⚡ Fast · Furious · Animated ⚡ Fast · Furious · Animated ⚡
</InfiniteRibbon>
</div>
<div className="space-y-2">
<p className="font-medium text-sm">Tilted marquee</p>
<div className="rounded-md border bg-muted/30 py-6">
<InfiniteRibbon repeat={3} duration={12} rotation={-3} className="bg-emerald-400 text-black dark:bg-emerald-500">
🎉 JolyUI · Hand-crafted components for React 🎉
</InfiniteRibbon>
</div>
</div>
</div>
);
}API Reference
InfiniteRibbon Props
Prop
Type
Notes
- Pure CSS keyframe animation — no
motionor other runtime libraries required - Track is internally duplicated (
repeat * 2) for seamless looping reverseflips the scroll direction without changing the visual orderrotationlets you tilt the ribbon for diagonal marquee effectsprefers-reduced-motionis honored — animation duration collapses to 1ms- Children are wrapped in a
sr-onlyaccessible label so the ribbon stays screen-reader friendly - Great for hero announcements, news tickers, promotional banners and CTA strips
How is this guide?
Highlight Text
Animated text highlighter for React. SVG underlines, boxes, circles, and marker effects. Draw attention to key words with hand-drawn style animations.
Number Counter
Animated number counter for React. Rolling digits, circular progress, and stats counters. Perfect for dashboards, pricing pages, and landing pages.