Marquee
Infinite scrolling marquee with smooth animations and user controls.
Features
- ✅ Infinite horizontal or vertical scrolling
- ✅ Auto-fill content duplication for seamless loop
- ✅ Configurable speed and direction
- ✅ Pause on hover or focus
- ✅ Manual play/pause controls
- ✅ Respects
prefers-reduced-motion - ✅ GPU-accelerated CSS animations
- ✅ RTL support
Accessibility
Marquees can be distracting for users with attention deficits or cognitive disabilities. Use them sparingly and primarily for decorative content. Always provide pause controls and respect user motion preferences.
Required CSS
Add these styles to your stylesheet (one time setup):
/* Keyframe animations */
@keyframes marqueeX {
to { transform: translateX(var(--marquee-translate)); }
}
@keyframes marqueeY {
to { transform: translateY(var(--marquee-translate)); }
}
/* Base animation styles */
[data-scope="marquee"][data-part="content"] {
animation-duration: var(--marquee-duration);
animation-iteration-count: var(--marquee-loop-count);
}
/* Apply horizontal animation */
[data-part="content"][data-side="start"],
[data-part="content"][data-side="end"] {
animation-name: marqueeX;
}
/* Apply vertical animation */
[data-part="content"][data-side="top"],
[data-part="content"][data-side="bottom"] {
animation-name: marqueeY;
}
/* Respect reduced motion preference */
@media (prefers-reduced-motion: reduce) {
[data-part="content"] {
animation: none !important;
}
}CSS Variables
The component automatically sets --marquee-duration based on your speed prop. The marquee uses contentCount to determine how many content tracks to render for seamless looping.
Basic Usage
With Manual Controls
Custom Speed
Reverse Direction
Vertical Orientation
Logo Carousel
Start Paused
Start with animation paused using defaultPaused:
Delayed Start
Delay animation start using delay prop (in milliseconds):
Limited Loops
Limit animation to specific number of loops using loopCount:
Pause on Focus
Marquee pauses when it receives keyboard focus (enabled by default):
Tab to focus the marquee - it will pause
API Reference
Root Props
| Property | Type | Default | Description |
|---|---|---|---|
vertical | boolean | false | Use vertical scrolling instead of horizontal |
reverse | boolean | false | Reverse animation direction |
speed | number | 50 | Animation speed in pixels per second |
pauseOnHover | boolean | true | Pause animation on mouse hover |
pauseOnFocus | boolean | true | Pause animation when marquee receives keyboard focus |
defaultPaused | boolean | false | Start in paused state |
delay | number | 0 | Delay before animation starts (in milliseconds) |
loopCount | number | Infinity | Number of times to loop the animation (infinite by default) |
Parts
| Part | Description |
|---|---|
x-marquee | Root container element |
x-marquee:viewport | Scrolling viewport with overflow hidden |
x-marquee:content | Content container (duplicated for loop) |
x-marquee:item | Individual scrolling items |
x-marquee:control | Play/pause toggle button |
Data Attributes
| Attribute | Values | Description |
|---|---|---|
data-state | playing | paused | Current animation state |
data-vertical | true | false | Whether vertical mode is enabled |
data-reverse | true | false | Whether reverse mode is enabled |
data-pause-on-hover | true | false | Whether pause on hover is enabled |
data-pause-on-focus | true | false | Whether pause on focus is enabled |
data-scope | marquee | Identifies component scope |
data-part | Part name | Identifies component part |
Methods
Access via $marquee magic:
| Method | Description |
|---|---|
play() | Start animation (respects delay on first play) |
pause() | Pause animation |
resume() | Resume animation from current position |
restart() | Restart animation from beginning |
toggle() | Toggle between play and pause |
Events
| Event | Detail | Description |
|---|---|---|
play | - | Fired when animation starts |
pause | - | Fired when animation pauses |
pause-change | { paused: boolean } | Fired when pause state changes |
loop-complete | { loop: number } | Fired after each animation loop completes |
complete | { totalLoops: number } | Fired when all loops finish (only with finite loopCount) |
Accessibility
- Automatically respects
prefers-reduced-motion- animation will not start if user prefers reduced motion - Provides pause on hover and focus for better control
- Includes proper ARIA labels on control button
- Recommended for decorative content only
- Consider providing alternative static content for users who cannot view animations
Keyboard Support
Focus the viewport and press Space to pause/play (when pauseOnFocus is enabled).
Best Practices
- Use sparingly - Marquees can be distracting and should be reserved for decorative content
- Provide controls - Always include a pause button for user control
- Respect motion preferences - The component automatically respects
prefers-reduced-motion - Keep content concise - Short, digestible content works best in marquees
- Consider alternatives - Static carousels or grids may be more accessible for important content