Skip to content

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):

css
/* 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

Item 1Item 2Item 3Item 4

With Manual Controls

News 1News 2News 3

Custom Speed

Fast Item 1Fast Item 2Fast Item 3

Reverse Direction

← Item 1← Item 2← Item 3

Vertical Orientation

Vertical 1Vertical 2Vertical 3Vertical 4
Logo 1Logo 2Logo 3Logo 4Logo 5

Start Paused

Start with animation paused using defaultPaused:

Paused Item 1Paused Item 2Paused Item 3

Delayed Start

Delay animation start using delay prop (in milliseconds):

Delayed Item 1Delayed Item 2Delayed Item 3

Limited Loops

Limit animation to specific number of loops using loopCount:

Loop Item 1Loop Item 2Loop Item 3
Loops completed: / 3✓ Animation complete!

Pause on Focus

Marquee pauses when it receives keyboard focus (enabled by default):

Focus Item 1Focus Item 2Focus Item 3

Tab to focus the marquee - it will pause

API Reference

Root Props

PropertyTypeDefaultDescription
verticalbooleanfalseUse vertical scrolling instead of horizontal
reversebooleanfalseReverse animation direction
speednumber50Animation speed in pixels per second
pauseOnHoverbooleantruePause animation on mouse hover
pauseOnFocusbooleantruePause animation when marquee receives keyboard focus
defaultPausedbooleanfalseStart in paused state
delaynumber0Delay before animation starts (in milliseconds)
loopCountnumberInfinityNumber of times to loop the animation (infinite by default)

Parts

PartDescription
x-marqueeRoot container element
x-marquee:viewportScrolling viewport with overflow hidden
x-marquee:contentContent container (duplicated for loop)
x-marquee:itemIndividual scrolling items
x-marquee:controlPlay/pause toggle button

Data Attributes

AttributeValuesDescription
data-stateplaying | pausedCurrent animation state
data-verticaltrue | falseWhether vertical mode is enabled
data-reversetrue | falseWhether reverse mode is enabled
data-pause-on-hovertrue | falseWhether pause on hover is enabled
data-pause-on-focustrue | falseWhether pause on focus is enabled
data-scopemarqueeIdentifies component scope
data-partPart nameIdentifies component part

Methods

Access via $marquee magic:

MethodDescription
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

EventDetailDescription
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

  1. Use sparingly - Marquees can be distracting and should be reserved for decorative content
  2. Provide controls - Always include a pause button for user control
  3. Respect motion preferences - The component automatically respects prefers-reduced-motion
  4. Keep content concise - Short, digestible content works best in marquees
  5. Consider alternatives - Static carousels or grids may be more accessible for important content

Built with Alpine.js and inspired by Zag.js