Marquee.tsx
Animated scrolling marquee component for displaying repeating content
The Marquee component creates smooth, infinite scrolling animations for displaying logos, testimonials, or any repeating content.
Features
- Horizontal or vertical scrolling
- Configurable animation speed
- Pause on hover option
- Reverse direction support
- Customizable repeat count
- Smooth CSS animations
Basic Usage
import { Marquee } from '@/components/ui/Marquee';
export default function Page() {
return (
<Marquee>
<div className="mx-4">Item 1</div>
<div className="mx-4">Item 2</div>
<div className="mx-4">Item 3</div>
<div className="mx-4">Item 4</div>
</Marquee>
);
}Logo Showcase
import { Marquee } from '@/components/ui/Marquee';
import Image from 'next/image';
export default function LogoMarquee() {
const logos = [
{ name: 'Company 1', src: '/logos/company1.png' },
{ name: 'Company 2', src: '/logos/company2.png' },
{ name: 'Company 3', src: '/logos/company3.png' },
];
return (
<Marquee pauseOnHover className="[--duration:20s]">
{logos.map((logo) => (
<div key={logo.name} className="mx-8">
<Image
src={logo.src}
alt={logo.name}
width={120}
height={40}
className="opacity-50 hover:opacity-100 transition-opacity"
/>
</div>
))}
</Marquee>
);
}Testimonials
import { Marquee } from '@/components/ui/Marquee';
import { Card, CardContent } from '@/components/ui/Card';
export default function TestimonialMarquee() {
const testimonials = [
{ name: 'John Doe', text: 'Great product!' },
{ name: 'Jane Smith', text: 'Highly recommend!' },
{ name: 'Bob Johnson', text: 'Amazing experience!' },
];
return (
<Marquee pauseOnHover className="[--duration:30s]">
{testimonials.map((testimonial) => (
<Card key={testimonial.name} className="mx-4 w-[300px]">
<CardContent className="p-4">
<p className="text-sm">{testimonial.text}</p>
<p className="text-xs text-neutral-foreground mt-2">
- {testimonial.name}
</p>
</CardContent>
</Card>
))}
</Marquee>
);
}Vertical Marquee
<Marquee vertical className="h-[400px]">
<div className="my-4">Item 1</div>
<div className="my-4">Item 2</div>
<div className="my-4">Item 3</div>
</Marquee>Reverse Direction
<Marquee reverse>
<div className="mx-4">Item 1</div>
<div className="mx-4">Item 2</div>
<div className="mx-4">Item 3</div>
</Marquee>Custom Speed
Control animation speed with CSS variable:
<Marquee className="[--duration:10s]">
<div className="mx-4">Fast scrolling</div>
</Marquee>
<Marquee className="[--duration:60s]">
<div className="mx-4">Slow scrolling</div>
</Marquee>Custom Gap
Adjust spacing between items:
<Marquee className="[--gap:2rem]">
<div>Item 1</div>
<div>Item 2</div>
<div>Item 3</div>
</Marquee>Multiple Rows
Create multiple marquee rows with different directions:
<div className="space-y-4">
<Marquee className="[--duration:20s]">
<div className="mx-4">Row 1 - Item 1</div>
<div className="mx-4">Row 1 - Item 2</div>
</Marquee>
<Marquee reverse className="[--duration:25s]">
<div className="mx-4">Row 2 - Item 1</div>
<div className="mx-4">Row 2 - Item 2</div>
</Marquee>
</div>Implementation
The Marquee uses CSS animations defined in globals.css:
@theme inline {
--animate-marquee: marquee var(--duration) infinite linear;
--animate-marquee-vertical: marquee-vertical var(--duration) linear infinite;
@keyframes marquee {
from {
transform: translateX(0);
}
to {
transform: translateX(calc(-100% - var(--gap)));
}
}
@keyframes marquee-vertical {
from {
transform: translateY(0);
}
to {
transform: translateY(calc(-100% - var(--gap)));
}
}
}Props
interface IMarqueeProps {
className?: string;
reverse?: boolean; // Reverse animation direction
pauseOnHover?: boolean; // Pause on hover
vertical?: boolean; // Vertical scrolling
repeat?: number; // Number of repetitions (default: 4)
children: React.ReactNode;
}CSS Variables
--duration: Animation duration (default: 40s)--gap: Gap between items (default: 1rem)
Best Practices
- Use
pauseOnHoverfor interactive content - Adjust
repeatbased on content width - Set appropriate
--durationfor smooth scrolling - Use consistent spacing between items
- Ensure content is readable at scroll speed
How is this guide ?
Last updated on