
Peek is a tiny, dependency-free JavaScript library that hides your fixed header navwhen a user scrolls down and reveals it when they scroll back up.
It reads scroll intent rather than raw scroll position, so the header only transitions after the user has moved a meaningful number of pixels in a given direction.
The result is a cleaner browsing experience on content-heavy pages. The header gets out of the way on the way down, and comes back the moment the user signals they want to navigate.
Features:
- Scroll intent detection: A configurable tolerance threshold filters out micro-movements and accidental jitter before any state change fires.
requestAnimationFramescheduling: All DOM updates run insiderAFcalls.- Passive scroll listeners: The scroll event is attached with
{ passive: true }. This unlocks browser-level scroll optimizations and avoids blocking the main thread. - CSS class-based API: Peek applies and removes classes on your header element. Your CSS owns the animation logic entirely.
- Configurable offset and tolerance: You control exactly when and how sensitively the header responds to scroll changes.
See It In Action:
Use Cases:
- Long-form content sites: On articles or documentation pages, the fixed header can cover a significant portion of the viewport. Peek hides it as soon as the user starts reading, then brings it back the moment they scroll up to navigate.
- Mobile-first interfaces: Screen real estate is at a premium on mobile. Peek’s mobile-only initialization pattern lets you apply the behavior exclusively on small viewports and tear it down on larger ones.
- E-commerce product pages: Product detail pages often have tall layouts. Hiding the header on scroll down keeps the product imagery and copy in full view, and the cart/nav reappear as soon as the user scrolls up.
How To Use It:
1. Download peek.js and include it before your closing </body> tag:
<link rel="stylesheet" href="src/peek.css" /> <script src="src/peek.js"></script>
2. Add the ‘main-header’ class to your header navigation.
<header class="main-header"> Your Header Nav Here </header>
3. Initialize peek.js with default opitons.
const peek = Peek('.main-header');4. Config the behavitor of peek.js with the following confiugration options.
offset(Number): The scroll distance in pixels from the top of the page before Peek begins evaluating pin/unpin behavior. The header stays pinned for any scroll position at or below this value. Default:100.tolerance(Number): The minimum number of pixels the user must scroll in a single direction before Peek changes the pin state. This filters out accidental micro-scrolls and touch jitter. Default:5.classes.pinned(String): The class applied to the header element when it should be visible (i.e., when the user scrolls up or is at the top of the page). Default:'main-header--pinned'.classes.unpinned(String): The class applied to the header element when it should be hidden (i.e., when the user scrolls down past the offset). Default:'main-header--unpinned'.classes.top(String): The class applied whenscrollYis at or below theoffsetvalue. Use this to style the header differently when sitting above the page content — for example, a transparent background over a hero image. Default:'main-header--top'.classes.notTop(String): The class applied whenscrollYexceeds theoffsetvalue. Use this to add a background color or drop shadow once the user has scrolled into the page body. Default:'main-header--not-top'.
const peek = Peek('.main-header',{
offset: 100,
tolerance: 5,
classes: {
pinned: 'main-header--pinned',
unpinned: 'main-header--unpinned',
top: 'main-header--top',
notTop: 'main-header--not-top',
},
});5. Removes the scroll event listener and strips all Peek-managed classes from the header element. Call this when you need to cleanly tear down the behavior. For example, before a framework route change or on resize when swapping between mobile and desktop modes.
peek.destroy();
6. Here is an example on how to create a smart, mobile-only header nav.
let peek;
function initPeekOnMobile() {
if (window.innerWidth < 768 && !peek) {
// Viewport is mobile-sized and Peek is not yet running — initialize it
peek = Peek('.main-header');
} else if (window.innerWidth >= 768 && peek) {
// Viewport has grown to desktop size — tear down to keep header always visible
peek.destroy();
peek = null;
}
}
initPeekOnMobile();
// Re-evaluate on every resize (consider debouncing for production)
window.addEventListener('resize', initPeekOnMobile);Alternatives:
FAQs:
Q: The header flickers between pinned and unpinned when I scroll slowly. How do I fix it?
A: Increase the tolerance value. Start at 10 and tune from there.
Q: Can I use Peek with a CSS framework like Tailwind or Bootstrap?
A: Yes. Peek applies classes to your element. It has no opinion on what those classes do or where they come from.
Q: The header stays hidden after a programmatic scroll (e.g., scrollTo). Is this a known issue?
A: Programmatic scrolls fire the native scroll event, so Peek should respond normally. The most common cause of this symptom is a scrollDelta of 0 on the first frame after the scroll completes, which does not meet the tolerance threshold and leaves the state unchanged. Calling peek.destroy() and re-initializing after the programmatic scroll is a reliable workaround.
Q: Is Peek suitable for headers inside a scrolling container rather than the main window?
A: In its current form, no. Peek listens exclusively to the window scroll event. If your scrollable area is a div with overflow: auto, you would need to modify the source to attach the listener to that element and read its scrollTop property in place of window.pageYOffset.







