scroll-reactive-nav
v1.1.5
Published
A lightweight TypeScript library for intelligent scroll-aware navigation behavior
Maintainers
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-navVia 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
requestAnimationFramepolyfills) - 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
requestAnimationFramefor 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 buildLicense
MPL-2.0
