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

scroll-reactive-nav

v1.1.5

Published

A lightweight TypeScript library for intelligent scroll-aware navigation behavior

Readme

Scroll Reactive Navigation

Hide and show your navigation based on scroll direction.

The Navigation disappears as you scroll down, reappears when scrolling up. An elegant pattern that anticipates user intent and responds accordingly.

Inspired by mobile Safari's chrome behavior and adopted by sites like Medium and Teehan+Lax.

How is it different from Headroom.js?

While similar in concept to headroom.js, this library focuses on key improvements:

Natural scroll behavior - Header initially scrolls out naturally like static content

🎯 Smart reappearance - Fixed positioning only when scrolling up, respecting scroll tolerance

🎨 Minimal & opinionated - Smaller footprint with sensible defaults

Enhanced performance - Optimized RAF usage and passive event listeners

Features

  • Smart show/hide navigation on scroll with configurable tolerance
  • Natural initial scroll behavior (non-sticky until needed)
  • Bottom-of-page reappearance for better UX
  • Zero dependencies with full TypeScript support
  • RequestAnimationFrame optimization for 60fps smoothness
  • SSR-compatible with proper browser detection
  • Passive event listeners for better scroll performance
  • Customizable CSS classes and behavior options

Bundle Size

ScrollReactiveNav is incredibly lightweight:

  • ES Module: 3.92 KB (1.22 KB gzipped)
  • UMD Bundle: 2.67 KB (1.05 KB gzipped)
  • TypeScript Declarations: 2.75 KB
  • Total Package: ~6.6 KB unpacked

Built with Vite 7 for optimal tree-shaking and modern bundle optimization.

Installation

Via npm/pnpm/bun

npm install scroll-reactive-nav
# oder
pnpm add scroll-reactive-nav
# oder
bun add scroll-reactive-nav

Via ES6 Module (Development)

<script type="module">
  import { ScrollReactiveNav } from '/src/index.ts';

  const header = document.getElementById('header');
  const nav = new ScrollReactiveNav(header);
</script>

Quick Start

<!-- HTML -->
<header id="header">
  <nav>Your Navigation</nav>
</header>

<script type="module">
  import { ScrollReactiveNav } from 'scroll-reactive-nav';

  const header = document.getElementById('header');
  const nav = new ScrollReactiveNav(header);
</script>

Advanced Configuration

import { ScrollReactiveNav } from 'scroll-reactive-nav';

const nav = new ScrollReactiveNav(document.querySelector('.header'), {
  startOffset: 200,      // Scroll position when logic activates
  tolerance: 8,          // Minimum scroll distance for state changes
  showAtBottom: true,    // Show navigation at page bottom
  classNames: {
    base: 'scroll-nav',
    fixed: 'scroll-nav--fixed',
    hidden: 'scroll-nav--hidden'
  }
});

CSS

Add the essential CSS styles:

/* Base class */
.scroll-nav {
  transition: transform 0.3s ease;
  will-change: transform;
  z-index: 1000;
}

/* Fixed state */
.scroll-nav--fixed {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  width: 100%;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

/* Hidden state */
.scroll-nav--hidden {
  transform: translateY(-100%);
}

/* Optional: Prevent content jump when fixing */
.scroll-nav--fixed + * {
  margin-top: var(--scroll-nav-height, 0px);
}

Configuration Options

The ScrollReactiveNav class accepts these options as the second parameter:

Complete Options

const nav = new ScrollReactiveNav(header, {
  startOffset: 100,        // Height where logic activates
  tolerance: 8,            // Scroll tolerance in pixels
  showAtBottom: true,      // Show navigation at page bottom
  classNames: {
    base: 'scroll-nav',           // Base CSS class
    fixed: 'scroll-nav--fixed',   // Class for fixed state
    hidden: 'scroll-nav--hidden'  // Class for hidden state
  }
});

Option Details

| Option | Type | Default | Description | |--------|------|---------|-------------| | startOffset | number | element.offsetHeight | Pixel offset where scroll logic activates | | tolerance | number | 8 | Minimum scroll distance before changes occur | | showAtBottom | boolean | true | Show navigation when page bottom is reached | | classNames.base | string | 'scroll-nav' | Base CSS class for the element | | classNames.fixed | string | 'scroll-nav--fixed' | CSS class for fixed state | | classNames.hidden | string | 'scroll-nav--hidden' | CSS class for hidden state |

API Methods

init()

Initializes scroll monitoring (called automatically on creation).

nav.init();

destroy()

Removes all event listeners and CSS classes.

nav.destroy();

reset()

Resets navigation to original state.

nav.reset();

fix()

Fixes navigation to top of viewport.

nav.fix();

hide()

Hides the navigation.

nav.hide();

Static Methods

ScrollReactiveNav.isSupported()

Checks if browser supports required features.

if (ScrollReactiveNav.isSupported()) {
  const nav = new ScrollReactiveNav(header);
}

Examples

Custom Tolerance

const nav = new ScrollReactiveNav(header, {
  tolerance: 15  // Navigation reacts after 15px scroll difference
});

No Bottom Show

const nav = new ScrollReactiveNav(header, {
  showAtBottom: false  // Navigation stays hidden at bottom
});

Custom CSS Classes

const nav = new ScrollReactiveNav(header, {
  classNames: {
    base: 'my-nav',
    fixed: 'my-nav--stick',
    hidden: 'my-nav--hide'
  }
});

Browser Support

  • Modern browsers (Chrome, Firefox, Safari, Edge)
  • IE11+ (with requestAnimationFrame polyfills)
  • Mobile Safari (iOS)
  • Chrome Mobile (Android)

TypeScript

Fully written in TypeScript with complete type definitions:

import {
  ScrollReactiveNav,
  ScrollReactiveNavOptions,
  ScrollReactiveNavClassNames,
  ScrollReactiveNavInstance
} from 'scroll-reactive-nav';

Performance

  • Uses requestAnimationFrame for smooth animations
  • Passive event listeners for better scroll performance
  • Minimal DOM access through intelligent state management
  • Zero external dependencies

Development

# Install dependencies
bun install

# Start development server
bun run dev

# Build for production
bun run build

License

MPL-2.0