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

@preline/scrollspy

v4.2.0

Published

Preline UI is an open-source set of prebuilt UI components based on the utility-first Tailwind CSS framework.

Downloads

1,776

Readme

Scrollspy

Automatically update navigation or list group components based on scroll position to indicate which link is currently active in the viewport.

npm License: MIT Demo

Contents

Overview

The Scrollspy component automatically highlights navigation links based on the scroll position of the page. It tracks which section is currently visible in the viewport and updates the corresponding navigation item accordingly.

Key Features:

  • Automatic navigation highlighting based on scroll position
  • Customizable scroll offset
  • Support for custom scrollable containers
  • Programmatic control via JavaScript API
  • Event system for scroll tracking
  • Accessibility support

Installation

To get started, install Scrollspy plugin via npm, else you can skip this step if you are already using Preline UI as a package.

npm i @preline/scrollspy

CSS

Use @source to register the plugin's JavaScript path for Tailwind CSS scanning, then @import the plugin's CSS files into your Tailwind CSS file.

@import "tailwindcss";

/* @preline/scrollspy */
@source "../node_modules/@preline/scrollspy/*.js";
@import "./node_modules/@preline/scrollspy/variants.css";
@import "./node_modules/@preline/scrollspy/theme.css";

JavaScript

Include the JavaScript that powers the interactive elements near the end of your </body> tag:

<script src="./node_modules/@preline/scrollspy/index.js"></script>

Manual Initialization

Use the non-auto entry if you need manual initialization. In this mode, automatic initialization on page load is not included, so the component should be initialized explicitly.

<script type="module">
  import HSScrollspy from "@preline/scrollspy/non-auto.mjs";

  new HSScrollspy(document.querySelector("#scrollspy"));
</script>

Via Bundler

When using a bundler (Vite, webpack, etc.), import the plugin directly as an ES module.

@preline/scrollspy is the auto-init entry: it scans the DOM and initializes matching elements automatically.

import "@preline/scrollspy";

@preline/scrollspy/non-auto is the manual entry: use it when you want explicit control over when initialization happens, either via autoInit() or by creating a specific instance yourself.

import HSScrollspy from "@preline/scrollspy/non-auto";

HSScrollspy.autoInit();

// Or initialize a specific element manually
const el = document.querySelector("#scrollspy");
if (el) new HSScrollspy(el);

TypeScript

This package ships with TypeScript type definitions. No additional @types/ package is needed.

Basic usage

The following example demonstrates the minimal HTML structure required for a scrollspy component. This is a base template without custom styling - you can apply your own CSS classes and styles as needed. The navigation links are automatically highlighted as you scroll through the sections.

<div id="hs-scrollspy-scrollable-parent-first" class="max-h-96 overflow-y-auto">
  <div data-hs-scrollspy="#hs-scrollspy-first" class="flex flex-wrap gap-3">
    <a class="active" href="#hs-first">First</a>
    <a href="#hs-second">Second</a>
    <a href="#hs-third">Third</a>
    <a href="#hs-fourth">Fourth</a>
    <a href="#hs-fifth">Fifth</a>
  </div>

  <div id="hs-scrollspy-first">
    <div id="hs-first" class="h-48">
      First
    </div>
    <div id="hs-second" class="h-48">
      Second
    </div>
    <div id="hs-third" class="h-48">
      Third
    </div>
    <div id="hs-fourth" class="h-48">
      Fourth
    </div>
    <div id="hs-fifth" class="h-48">
      Fifth
    </div>
  </div>
</div>

Structure Requirements:

  • data-hs-scrollspy: Required on the navigation container, must be a valid CSS selector pointing to the sections container
  • Navigation links with href attributes pointing to section IDs
  • Sections with matching id attributes
  • active class on the initially active navigation link

Initial State:

  • Add active class to the navigation link that corresponds to the initially visible section
  • Ensure sections have sufficient height to enable scrolling

Configuration Options

Data Attributes

Data attributes are added directly to HTML elements to configure scrollspy behavior.

| Attribute | Target Element | Type | Default | Description | | --- | --- | --- | --- | --- | | data-hs-scrollspy | Navigation container | string (CSS selector) | - | A container containing sections. This must be a valid CSS selector pointing to the sections container. Should be added to the nav that contains Scrollspy links. | | data-hs-scrollspy-scrollable-parent | Navigation container | string (CSS selector) | "window" | Specifies the element to be scrolled. This must be a valid CSS selector. Should be added to the nav that contains Scrollspy links. Defaults to window if not specified. |

CSS Classes (Modifiers)

CSS class modifiers use Tailwind-style syntax with -- prefix to control scrollspy behavior.

| Class Modifier | Target Element | Values | Default | Description | | --- | --- | --- | --- | --- | | [--scrollspy-offset:*] | Navigation container | number | 0 | Adds offset when scrolling to the section and to determine if the section is active. Useful for fixed headers or navigation bars. |

Example:

<div data-hs-scrollspy="#hs-sections" --scrollspy-offset:100>
  <!-- Navigation links -->
</div>

Tailwind Modifiers

| Name | Description | | --- | --- | | hs-scrollspy-active:* | A modifier that allows you to set Tailwind classes when the section is active for the corresponding link. |

JavaScript API

The HSScrollspy object is available in the global window object after the plugin is loaded.

Instance Methods

These methods are called on a scrollspy instance.

| Method | Parameters | Return Type | Description | | --- | --- | --- | --- | | destroy() | None | void | Destroys the scrollspy instance, removes all generated markup, classes, and event listeners. Use when removing scrollspy from DOM. |

Static Methods

These methods are called directly on the HSScrollspy class.

| Method | Parameters | Return Type | Description | | --- | --- | --- | --- | | HSScrollspy.getInstance(target, isInstance) | target: HTMLElement \| string (CSS selector)isInstance: boolean (optional) | HTMLElement \| { id: string \| number, element: HSScrollspy } \| null | Returns the scrollspy instance or element associated with the target. If isInstance is true, returns collection item object { id, element } where element is the HSScrollspy instance. If isInstance is false or omitted, returns the DOM element (HTMLElement). Returns null if scrollspy instance is not found. |

Usage Examples

Example 1: Destroying scrollspy instance

const instance = HSScrollspy.getInstance('#hs-scrollspy', true);

if (instance) {
  const { element } = instance;
  const destroyBtn = document.querySelector('#hs-destroy-btn');

  destroyBtn.addEventListener('click', () => {
    element.destroy();
  });
}

Example 2: Getting instance and using methods (recommended pattern)

// Get the scrollspy instance
const instance = HSScrollspy.getInstance('[data-hs-scrollspy="#hs-scrollspy"]', true);

if (instance) {
  const { element } = instance;

  // Access instance properties
  console.log('Scrollspy links:', element.links);
  console.log('Scrollspy sections:', element.sections);

  // Clean up when removing from DOM
  function removeScrollspy() {
    element.destroy();
  }
}

Events

Scrollspy instances emit events that can be listened to for scroll tracking and custom behavior.

| Event Name | When Fired | Callback Parameter | Description | | --- | --- | --- | --- | | on:beforeScroll | Before scrolling begins | HSScrollspy (scrollspy instance) | Fires before scrolling to a section begins. Can return a Promise to delay scrolling until async operations complete. Useful for animations or other preparations. |

Event Usage Example

// Get scrollspy instance
const instance = HSScrollspy.getInstance('[data-hs-scrollspy="#hs-scrollspy"]', true);

if (instance) {
  const { element } = instance;
  const collapse = HSCollapse.getInstance('[data-hs-collapse="#hs-navbar-collapse"]', true);

  // Listen to beforeScroll event
  element.on('beforeScroll', (scrollspyInstance) => {
    return new Promise((resolve) => {
      if (collapse && collapse.element.el.classList.contains('open')) {
        collapse.element.hide();
        HSStaticMethods.afterTransition(collapse.element.content, () => resolve(true));
      } else {
        resolve(true);
      }
    });
  });
}

Common Patterns

Pattern 1: Custom Scrollable Container

Use scrollspy with a custom scrollable container instead of the window.

<div id="hs-scrollable-container" class="max-h-96 overflow-y-auto">
  <nav data-hs-scrollspy="#hs-sections" data-hs-scrollspy-scrollable-parent="#hs-scrollable-container">
    <a href="#hs-section-first">Section 1</a>
    <a href="#hs-section-second">Section 2</a>
  </nav>
  
  <div id="hs-sections">
    <div id="hs-section-first">Content 1</div>
    <div id="hs-section-second">Content 2</div>
  </div>
</div>

Pattern 2: With Offset

Add offset for fixed navigation bars.

<nav data-hs-scrollspy="#hs-sections" --scrollspy-offset:100>
  <!-- Navigation links -->
</nav>

License

Copyright (c) 2026 Preline Labs.

Licensed under the MIT License.