A lightweight TypeScript library for intelligent scroll-aware navigation behavior
npm install scroll-reactive-navHide 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.
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
- 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
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.
``bash`
npm install scroll-reactive-navoder
pnpm add scroll-reactive-navoder
bun add scroll-reactive-nav
`html`
`html
`
`typescript
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'
}
});
`
Add the essential CSS styles:
`css
/ 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);
}
`
The ScrollReactiveNav class accepts these options as the second parameter:
`typescript`
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 | 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 |
`typescript`
nav.init();
`typescript`
nav.destroy();
`typescript`
nav.reset();
`typescript`
nav.fix();
`typescript`
nav.hide();
`typescript`
if (ScrollReactiveNav.isSupported()) {
const nav = new ScrollReactiveNav(header);
}
`typescript`
const nav = new ScrollReactiveNav(header, {
tolerance: 15 // Navigation reacts after 15px scroll difference
});
`typescript`
const nav = new ScrollReactiveNav(header, {
showAtBottom: false // Navigation stays hidden at bottom
});
`typescript`
const nav = new ScrollReactiveNav(header, {
classNames: {
base: 'my-nav',
fixed: 'my-nav--stick',
hidden: 'my-nav--hide'
}
});
- Modern browsers (Chrome, Firefox, Safari, Edge)
- IE11+ (with requestAnimationFrame polyfills)
- Mobile Safari (iOS)
- Chrome Mobile (Android)
Fully written in TypeScript with complete type definitions:
`typescript`
import {
ScrollReactiveNav,
ScrollReactiveNavOptions,
ScrollReactiveNavClassNames,
ScrollReactiveNavInstance
} from 'scroll-reactive-nav';
- Uses requestAnimationFrame for smooth animations
- Passive event listeners for better scroll performance
- Minimal DOM access through intelligent state management
- Zero external dependencies
`bashInstall dependencies
bun install
MPL-2.0