Marquee
The Marquee component creates an infinite scrolling effect perfect for displaying logos, testimonials, or any content that needs continuous horizontal movement. Features smooth CSS animations with pause-on-hover support.
Installation
npm install @craftdotui/components
Import
import Marquee from "@craftdotui/components" ;
Usage
Basic Marquee
Logo Showcase
Reverse Direction
import Marquee from "@craftdotui/components" ;
export default function Example () {
return (
< Marquee >
< div className = "flex gap-8" >
< span className = "text-2xl font-bold" > Item 1 </ span >
< span className = "text-2xl font-bold" > Item 2 </ span >
< span className = "text-2xl font-bold" > Item 3 </ span >
< span className = "text-2xl font-bold" > Item 4 </ span >
</ div >
</ Marquee >
);
}
Props
The content to scroll. Typically a flex container with items.
Animation duration in seconds. Lower values = faster scrolling.
Number of times to repeat the content. Minimum 2 recommended for seamless loops.
direction
'left' | 'right'
default: "'left'"
Scroll direction.
Whether to pause animation when hovering.
Gap between repeated content instances in pixels.
Additional CSS classes for the container.
Animation Details
CSS Keyframes
The component uses pure CSS animations for optimal performance:
@keyframes marquee-left {
0% { transform : translateX ( 0 ); }
100% { transform : translateX ( -100 % ); }
}
@keyframes marquee-right {
0% { transform : translateX ( -100 % ); }
100% { transform : translateX ( 0 ); }
}
Animation Properties
animation : `marquee- ${ direction } ${ duration } s linear infinite`
Timing : linear for constant speed
Iteration : infinite for continuous scrolling
Duration : Configurable via props
The repeat prop duplicates the content to ensure seamless infinite scrolling without gaps.
Examples
Partner Logos
import Marquee from "@craftdotui/components" ;
export default function PartnerLogos () {
const partners = [
{ name: "Google" , logo: "/partners/google.svg" },
{ name: "Microsoft" , logo: "/partners/microsoft.svg" },
{ name: "Apple" , logo: "/partners/apple.svg" },
{ name: "Amazon" , logo: "/partners/amazon.svg" },
{ name: "Meta" , logo: "/partners/meta.svg" },
];
return (
< div className = "py-12 bg-gray-50" >
< h2 className = "text-center text-2xl font-bold mb-8" > Trusted by industry leaders </ h2 >
< Marquee duration = { 40 } gap = { 64 } className = "py-4" >
{ partners . map (( partner , i ) => (
< img
key = { i }
src = { partner . logo }
alt = { partner . name }
className = "h-16 w-auto opacity-60 hover:opacity-100 transition-opacity"
/>
)) }
</ Marquee >
</ div >
);
}
Testimonials Scroll
import Marquee from "@craftdotui/components" ;
import { Star } from "lucide-react" ;
export default function Testimonials () {
const testimonials = [
{ text: "Amazing product!" , author: "John Doe" },
{ text: "Best service ever!" , author: "Jane Smith" },
{ text: "Highly recommended!" , author: "Bob Johnson" },
];
return (
< Marquee duration = { 50 } gap = { 32 } >
{ testimonials . map (( testimonial , i ) => (
< div key = { i } className = "bg-white p-6 rounded-lg shadow-md min-w-[300px]" >
< div className = "flex gap-1 mb-3" >
{ [ ... Array ( 5 )]. map (( _ , i ) => (
< Star key = { i } className = "w-4 h-4 fill-yellow-400 text-yellow-400" />
)) }
</ div >
< p className = "text-gray-700 mb-2" > " { testimonial . text } " </ p >
< p className = "text-sm text-gray-500" > - { testimonial . author } </ p >
</ div >
)) }
</ Marquee >
);
}
Dual Direction Marquees
import Marquee from "@craftdotui/components" ;
export default function DualMarquee () {
const skills = [
"React" , "TypeScript" , "Next.js" , "Tailwind CSS" ,
"Node.js" , "GraphQL" , "PostgreSQL" , "Docker"
];
return (
< div className = "space-y-4" >
< Marquee direction = "left" duration = { 30 } >
{ skills . map (( skill , i ) => (
< div key = { i } className = "px-6 py-3 bg-gradient-to-r from-blue-500 to-purple-500 text-white rounded-full font-semibold" >
{ skill }
</ div >
)) }
</ Marquee >
< Marquee direction = "right" duration = { 35 } >
{ skills . reverse (). map (( skill , i ) => (
< div key = { i } className = "px-6 py-3 bg-gradient-to-r from-pink-500 to-orange-500 text-white rounded-full font-semibold" >
{ skill }
</ div >
)) }
</ Marquee >
</ div >
);
}
News Ticker
import Marquee from "@craftdotui/components" ;
export default function NewsTicker () {
const news = [
"Breaking: New feature released!" ,
"Update: Server maintenance scheduled for tonight" ,
"Announcement: Join our webinar next week" ,
];
return (
< div className = "bg-black text-white py-2" >
< Marquee duration = { 25 } pauseOnHover = { true } >
{ news . map (( item , i ) => (
< span key = { i } className = "mx-8" >
< span className = "text-red-500 mr-2" > • </ span >
{ item }
</ span >
)) }
</ Marquee >
</ div >
);
}
For seamless scrolling, ensure your content width is sufficient. Use repeat={2} or higher to avoid visible gaps.
Best Practices
Performance
Uses CSS animations (GPU-accelerated)
No JavaScript required for animation loop
Minimal re-renders
Content Guidelines
Keep individual items similar in size for visual consistency
Use fixed widths for items when possible
Include enough items to fill the viewport width
Set appropriate gap values to prevent crowding
Speed Configuration
// Slow, elegant scroll
< Marquee duration = { 60 } >
// Medium speed (default)
< Marquee duration = { 20 } >
// Fast ticker
< Marquee duration = { 10 } >
Accessibility
Continuous motion can be problematic for users with vestibular disorders. Consider:
Setting pauseOnHover={true} (default)
Providing a pause/play control
Respecting prefers-reduced-motion media query
Use Cases
Logo showcases
Partner/sponsor displays
Testimonial carousels
News tickers
Social media feeds
Product highlights
Award badges
Technology stack displays