React Headroom: build an auto-hiding navigation header that feels native
Quick summary: react-headroom is a lightweight React component that automatically hides a header when the user scrolls down and reveals it when they scroll up — ideal for sticky navigation, saving vertical space, and improving perceived performance on mobile and desktop.
What react-headroom does and when to use it
react-headroom implements an auto-hiding header pattern with minimal setup. It observes scroll direction, toggles CSS states like pinned/unpinned, and exposes callbacks so you can coordinate animations, ARIA updates, or analytics. If you need a navigation header that disappears on downward scroll to maximize content area and reappears when the user scrolls back, this library is a pragmatic choice.
Because it’s focused solely on header visibility (not a full navigation framework), react-headroom pairs well with your existing React router, CSS-in-JS, or utility CSS. It supports simple use cases out of the box and more complex ones via props and lifecycle callbacks.
Use it when you want predictable, accessible behavior with low runtime overhead. Avoid it for headers that must always remain visible (for critical controls) or when you need complex, multi-element scroll-synced animations — combine it with IntersectionObserver or dedicated animation libraries in those cases.
Install and get started (fast path)
Install from npm or Yarn. The official package is published as react-headroom and available at the package registry. Run one of the commands below in your project root.
// npm
npm install react-headroom
// yarn
yarn add react-headroom
Then import and wrap your header. This minimal example shows the typical pattern: wrap the element you want to auto-hide in <Headroom></Headroom>.
import React from 'react';
import Headroom from 'react-headroom';
function AppHeader() {
return (
<Headroom>
<header className="site-header">
<nav>...</nav>
</header>
</Headroom>
);
}
For a guided walkthrough and extended examples, see this react-headroom tutorial: react-headroom tutorial. For the published package and installation details, visit the official registry: react-headroom installation.
How auto-hiding headers work: scroll detection, thresholds, and callbacks
At its core, react-headroom listens to window scroll events and compares the current scroll position to the last known position. If the user scrolls down beyond a configurable offset, the header transitions to an "unpinned" state (hidden). When the user scrolls up, it switches to a "pinned" state (visible). To avoid toggling on every minor scroll, the component uses tolerance values and an offset.
Key concepts to understand: offset, up/down tolerance, and callbacks. Offset is how far the page must scroll before the first hide can occur (useful to prevent hiding during initial page load). Tolerance compensates for micro-scroll jitter; small tolerances reduce flicker. Callbacks like onPin and onUnpin let you hook into state changes to trigger side effects (like updating ARIA attributes or starting an animation).
Example with basic callbacks and custom offsets:
import Headroom from 'react-headroom';
<Headroom
upTolerance={5}
downTolerance={5}
// number of pixels to wait before toggling
style={{ zIndex: 1000 }}
onPin={() => console.log('header shown')}
onUnpin={() => console.log('header hidden')}
>
<Header />
</Headroom>
For mobile performance, ensure you use passive listeners and avoid synchronous layout reads inside scroll handlers. react-headroom mitigates much of this, but expensive operations inside callbacks can still hurt scroll perf.
Customization, animations, and accessibility
react-headroom uses CSS class toggles to reflect state. The standard classes include headroom, headroom--pinned, and headroom--unpinned. You control animation by styling those classes. For example, use transform/translateY for GPU-accelerated movement and transitions for smoothness.
Disable inline styles if you prefer full CSS control using disableInlineStyles. Add your own transitions and keyframes for slide, fade, or compound animations. Keep animations short (150–300ms) so the header feels responsive when the user reverses scroll direction.
Accessibility tips: update ARIA attributes if the header contains navigation that must be always perceivable to screen reader users. For critical controls, consider making them sticky within the header content rather than hiding them completely. Also ensure that keyboard focus is preserved: avoid moving content in ways that steal focus, and if the header hides, do not disrupt tab order.
/* CSS (example)
.headroom { transition: transform 220ms ease-in-out; }
.headroom--unpinned { transform: translateY(-100%); }
.headroom--pinned { transform: translateY(0); }
Animations can be as simple or elaborate as you need. Keep the performance and accessibility trade-offs in mind when choosing fades, blurs, or heavy compositing effects.
Practical examples, edge cases and best practices
Combine react-headroom with a sticky element: if you have a small persistent toolbar, place it outside the Headroom wrapper so it remains visible. For multi-header layouts, either nest Headroom components (careful with z-index) or manage visibility state at a higher level and render headers conditionally.
Handle server-side rendering by checking for document/window existence before relying on scroll position in custom code. react-headroom itself is safe for typical SSR flows, but any callbacks that access window should guard against undefined references.
Performance best practices: avoid heavy work in onPin/onUnpin; debounce expensive operations; use transform instead of top/height; and prefer CSS transitions over JS-driven animations. Test on low-end mobile devices to ensure the header hides/reveals smoothly.
Examples and code patterns you’ll reuse
Here’s a slightly more complete example integrating a small logo and navigation, plus a dark mode toggle. Note how the component controls layout but leaves styling to CSS.
import Headroom from 'react-headroom';
export default function SiteHeader() {
return (
<Headroom pinStart={60} upTolerance={10} downTolerance={10}>
<header className="site-header">
<div className="brand">Logo</div>
<nav>...</nav>
<button aria-label="Toggle dark mode">🌓</button>
</header>
</Headroom>
);
}
Troubleshooting common issues: if the header doesn’t reappear, verify you haven’t blocked scroll events with pointer-capturing overlays; ensure z-index keeps the header above content; and inspect computed styles to confirm your CSS transitions are active on the expected classes.
Edge case — very short pages: on pages short enough not to scroll, react-headroom won’t unpin/pin because there is no scroll direction change; consider conditioning Headroom usage by page length if you need deterministic header behavior everywhere.
Semantic core (keywords & clusters)
- Primary queries
- react-headroom
- React auto-hiding header
- react-headroom tutorial
- React sticky navigation
- react-headroom installation
- Secondary queries & variations
- React scroll header
- react-headroom example
- React hide on scroll
- react-headroom setup
- React navigation header
- Clarifying / intent-based & LSI phrases
- react-headroom customization
- React scroll detection
- react-headroom animations
- React header library
- react-headroom getting started
- auto hide navbar react
- hide header on scroll up down react
- headroom css classes headroom–unpinned headroom–pinned
FAQ
How do I install react-headroom?
Install the package with npm or Yarn: npm install react-headroom or yarn add react-headroom. Then import Headroom from 'react-headroom' and wrap your header component. See the npm package page for details and changelog.
How can I customize animations and styles in react-headroom?
react-headroom toggles CSS classes based on state. Target .headroom--unpinned and .headroom--pinned in your stylesheet and use transform + transition for smooth, GPU-accelerated motion. If you prefer full control, set disableInlineStyles and provide all style rules in your CSS or CSS-in-JS.
How does react-headroom detect scroll and hide the header?
It compares current and previous scroll positions to infer direction. When the user scrolls down past an offset, the header is marked unpinned; when the user scrolls up, it becomes pinned. Tolerance values help reduce jitter; callbacks provide hooks for side effects.
Backlinks & resources
Further reading and packages used in examples:
- react-headroom tutorial — step-by-step guide and examples.
- react-headroom installation — official npm package page with install instructions and props list.