npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

comet-marquee

v1.1.22

Published

A lightweight, smooth-scrolling marquee plugin for modern browsers. Allows continuous horizontal scrolling of content with optional pause on hover or click.

Readme

CometMarquee

A lightweight, smooth-scrolling marquee plugin for modern browsers. Allows continuous horizontal scrolling of content with automatic performance optimization and accessibility features.


npm GitHub unpkg


Installation

npm/pnpm

npm install comet-marquee
# or
pnpm add comet-marquee
// Default import
import CometMarquee from 'comet-marquee';

// Or named import (if supported)
import { CometMarquee } from 'comet-marquee';

// CSS
import 'comet-marquee/dist/comet-marquee.css';

cdn (unpkg)

<script src="https://unpkg.com/comet-marquee@latest/dist/comet-marquee.umd.js"></script>
<link rel="stylesheet" href="https://unpkg.com/comet-marquee@latest/dist/comet-marquee.css">

HTML Structure

<div class="comet-marquee-container">
    <div class="comet-marquee-content">
        <div class="comet-marquee-item">Item 1</div>
        <div class="comet-marquee-item">Item 2</div>
        <div class="comet-marquee-item">Item 3</div>
        <!-- Optional: more items -->
    </div>
</div>

⚠️ Note: comet-marquee-item is recommended but not strictly required. All direct children of .comet-marquee-content will be used as items.

Usage

const marquee = new CometMarquee('.comet-marquee-container', {
  speed: 60,                // scroll speed (px/sec), default 50
  gap: 20,                  // gap between items in px, auto-detected from CSS
  pauseOnHover: true,       // pause when mouse hovers over the container
  pauseOnClick: true,       // pause when container is clicked (touch-friendly)
  adaptivePause: true,      // hover on desktop, click on mobile
  reverse: false,           // reverse scrolling direction
  initialShift: true,       // start with content shifted by container width
  pauseOnInvisible: true,   // pause when marquee is not visible
  syncPause: true,          // synchronize pause across all marquee instances
  repeatCount: 3,           // number of content repetitions for smooth animation
  forceAnimation: false,    // force animation even if content fits in container
  forceAnimationWidth: 2,   // multiplier for forced animation width (relative to window width)
  develop: false,            // enable debug console logging
  fadeEdges: false            // enables fade blurring at the edges
});

// Control methods
marquee.start();
marquee.stop();
marquee.pause();
marquee.resume();
marquee.refresh();

// Dynamic content manipulation
marquee.addItem('<div class="comet-marquee-item">New Item</div>');
marquee.removeItem(); // removes last original item

Options

| Option | Type | Default | Description | |--------|------|---------|----------------------------------------------------------------------------------------------------------------------------| | speed | number | 50 | Scrolling speed in pixels per second | | gap | number | CSS gap | Space between items in pixels (auto-detected from CSS if not specified) | | pauseOnHover | boolean | false | Pause marquee on mouse hover | | pauseOnClick | boolean | false | Pause/resume marquee on click, resume on click outside container | | adaptivePause | boolean | false | Automatically use hover behavior on desktop (≥1024px) and click behavior on mobile (<1024px) | | reverse | boolean | false | Reverse scrolling direction (right to left becomes left to right) | | initialShift | boolean/number | false | Initial content offset: true shifts by container width, number shifts by specified pixels | | pauseOnInvisible | boolean | false | Pause animation when marquee is not visible in viewport (uses IntersectionObserver) | | syncPause | boolean | false | Synchronize pause/resume across all CometMarquee instances on the page | | repeatCount | number | 3 | Number of content repetitions for seamless scrolling. Increase for short content, decrease for performance with many items | | forceAnimation | boolean | false | Force animation even when content fits within container width | | forceAnimationWidth | number | 2 | Width multiplier (relative to window width) used for forced animation calculations | | develop | boolean | false | Enable debug console logging for all events | | fadeEdges | boolean/number | false | Eenables fade blurring at the edges. If true, then it will always blur, if for example 1900, then it will blur starting from 1900px (for cases when you need to blur at high resolutions) |

Force Animation Feature

The forceAnimation option allows you to create scrolling animation even when the content naturally fits within the container. This is useful for design consistency or when you want scrolling effect regardless of content size.

const marquee = new CometMarquee('.marquee', {
  forceAnimation: true,        // Enable forced animation
  forceAnimationWidth: 3,      // Use 3x window width for calculations
  speed: 30                    // Slower speed works well with forced animation
});

When forceAnimation is enabled:

  • The plugin calculates how many clones are needed to fill the target width (forceAnimationWidth * window.innerWidth)
  • Animation runs even if original content fits in container
  • Dispatches force-animation-enabled and force-animation-calculated events
  • Automatically adjusts clone count for optimal performance

Methods

| Method | Description | |--------|-------------| | start() | Start or restart marquee animation | | stop() | Stop animation completely and cancel animation frames | | pause() | Pause animation temporarily (can be resumed) | | resume() | Resume paused animation and recalculate dimensions | | refresh() | Recalculate dimensions, rebuild clones, and restart animation | | addItem(html) | Add a new item dynamically from HTML string | | removeItem() | Remove the last original item (not clones) | | destroy() | Clean up all event listeners, observers, and animation frames |

Event System

CometMarquee dispatches custom events throughout its lifecycle, allowing you to hook into different stages of the marquee operation. All events are dispatched on the container element with the prefix comet-marquee:.

Event Usage

const container = document.querySelector('.comet-marquee-container');

// Listen to specific events
container.addEventListener('comet-marquee:animation-started', (e) => {
  console.log('Marquee animation started', e.detail);
});

container.addEventListener('comet-marquee:animation-cycle', (e) => {
  console.log('Animation completed a cycle', e.detail.direction);
});

container.addEventListener('comet-marquee:hover-pause', (e) => {
  console.log('Marquee paused on hover', e.detail.instance);
});

container.addEventListener('comet-marquee:force-animation-enabled', (e) => {
  console.log('Force animation activated', e.detail);
});

Available Events

Lifecycle Events

| Event | Description | Detail Properties | |-------|-------------|------------------| | init-start | Marquee initialization begins | instance, container | | init-complete | Marquee initialization completed | instance, container | | destroy-start | Marquee destruction begins | instance, container | | destroy-complete | Marquee destruction completed | instance, container |

Dimension & Setup Events

| Event | Description | Detail Properties | |-------|-------------|------------------| | dimensions-calculated | Container and content dimensions calculated | containerWidth, contentWidth, shouldAnimate, forceAnimationEnabled | | force-animation-enabled | Force animation was activated | originalContentWidth, containerWidth | | force-animation-calculated | Force animation clone count calculated | targetWidth, singleSetWidth, setsNeeded, clonesNeeded | | clones-creating | Content clones creation started | instance, container | | clones-created | Content clones created | cloneCount, repeatCount, clonedItems, forceAnimationEnabled | | content-setup | Content positioning and width setup completed | totalWidth, initialTranslate, forceAnimationEnabled |

Animation Events

| Event | Description | Detail Properties | |-------|-------------|------------------| | animation-started | Animation loop started | instance, container | | animation-stopped | Animation loop stopped | instance, container | | animation-paused | Animation paused | instance, container | | animation-resumed | Animation resumed | instance, container | | animation-cycle | Animation completed one full cycle | direction ('forward' or 'reverse') | | animation-skipped | Animation skipped (content fits in container) | instance, container | | animation-not-needed | Animation not needed (content doesn't overflow) | instance, container |

Interaction Events

| Event | Description | Detail Properties | |-------|-------------|------------------| | hover-pause | Paused due to mouse hover | instance, container | | hover-resume | Resumed after mouse leave | instance, container | | click-pause | Paused due to click | instance, container | | click-resume | Resumed due to click | instance, container | | outside-click-resume | Resumed due to click outside container | instance, container |

Visibility Events

| Event | Description | Detail Properties | |-------|-------------|------------------| | visibility-pause | Paused due to becoming invisible | instance, container | | visibility-resume | Resumed due to becoming visible | instance, container | | document-visible | Document became visible (tab focus) | instance, container | | document-hidden | Document became hidden (tab blur) | instance, container |

System Events

| Event | Description | Detail Properties | |-------|-------------|------------------| | container-resized | Container was resized | instance, container | | orientation-change | Device orientation changed | instance, container | | adaptive-pause-resize | Adaptive pause behavior recalculated on resize | instance, container | | reduced-motion-on | User enabled reduced motion preference | instance, container | | reduced-motion-off | User disabled reduced motion preference | instance, container |

Content Management Events

| Event | Description | Detail Properties | |-------|-------------|------------------| | refresh-start | Content refresh started | instance, container | | refresh-complete | Content refresh completed | instance, container | | item-adding | New item being added | itemHtml | | item-added | New item added successfully | newItem | | item-removing | Item being removed | removedItem | | item-removed | Item removed successfully | instance, container | | events-bound | Event listeners bound to container | instance, container |

Event Detail Object

All events include a detail object with at minimum:

  • instance - The CometMarqueeInstance that triggered the event
  • container - The DOM container element
  • Additional properties specific to each event type

Development Mode

Set develop: true in options to enable console logging of all events:

const marquee = new CometMarquee('.marquee', {
  develop: true  // Will log all events to console
});

Multi-Instance Support

CometMarquee supports multiple instances on the same page with global synchronization:

// Create multiple marquees
const marquee1 = new CometMarquee('.marquee-1', { syncPause: true });
const marquee2 = new CometMarquee('.marquee-2', { syncPause: true });

// All instances are tracked globally for synchronization
console.log(window.__allCometMarqueeInstances); // Array of all instances

// Listen to events from all instances
document.addEventListener('comet-marquee:animation-started', (e) => {
  console.log('Any marquee started:', e.detail.container);
});

Accessibility & Performance Features

  • Reduced Motion Support: Automatically pauses when user has prefers-reduced-motion: reduce set
  • Visibility Optimization: Can pause when not visible (with pauseOnInvisible option)
  • Tab Visibility: Pauses when browser tab becomes hidden
  • Responsive Behavior: Automatically recalculates on window resize and orientation change
  • Performance Optimized: Uses requestAnimationFrame and will-change CSS property
  • Smart Content Detection: Only animates when content width exceeds container width (unless forceAnimation is enabled)
  • Adaptive Interactions: Desktop hover vs mobile touch behavior with adaptivePause
  • Memory Management: Proper cleanup of observers, event listeners, and animation frames

Browser Support

| Browser | Minimum Version | |---------|-----------------| | Chrome | 64+ | | Firefox | 69+ | | Safari | 14+ | | Edge | 79+ | | iOS Safari | 14+ | | Android Chrome | 64+ |

Required APIs:

  • requestAnimationFrame
  • ResizeObserver
  • IntersectionObserver (for visibility detection)
  • CSS transform3d and will-change
  • ES6 classes and arrow functions
  • CustomEvent (for event system)
  • performance.now() (for smooth animation timing)

Note: Tested on Safari 15.6+. Earlier versions may work but are not officially supported.

Advanced Usage Examples

Synchronized Marquees

// Create multiple synchronized marquees
const marquee1 = new CometMarquee('.marquee-1', {
  syncPause: true,
  speed: 50
});

const marquee2 = new CometMarquee('.marquee-2', {
  syncPause: true,
  speed: 50,
  reverse: true  // Opposite direction
});

Responsive Marquee with Force Animation

const marquee = new CometMarquee('.marquee', {
  forceAnimation: true,
  forceAnimationWidth: 1.5,
  adaptivePause: true,
  pauseOnInvisible: true,
  develop: process.env.NODE_ENV === 'development'
});

// Listen for force animation events
marquee.containers[0].addEventListener('comet-marquee:force-animation-enabled', (e) => {
  console.log('Animation forced:', e.detail.originalContentWidth, 'px content in', e.detail.containerWidth, 'px container');
});

Dynamic Content Management

const marquee = new CometMarquee('.news-ticker', {
  speed: 40,
  pauseOnHover: true
});

// Add breaking news
function addBreakingNews(newsText) {
  const newsHtml = `<div class="comet-marquee-item breaking-news">${newsText}</div>`;
  marquee.addItem(newsHtml);
}

// Remove old news
function removeOldNews() {
  marquee.removeItem();
}

Notes

  • Content clones are automatically created and managed for seamless infinite scrolling
  • The plugin automatically calculates optimal number of repetitions based on content and container size
  • Event listeners and observers are automatically cleaned up when instances are destroyed
  • All instances are tracked globally in window.__allCometMarqueeInstances for synchronization features
  • Works on both desktop (mouse events) and touch devices (touch events)
  • Comprehensive event system allows deep integration with your application logic
  • Force animation feature enables consistent scrolling behavior regardless of content size
  • Performance optimized with proper frame timing and GPU acceleration via transform3d