React Headroom is a lightweight library that automatically hides and shows navigation headers based on scroll direction. When users scroll down, the header hides to maximize content space, and when they scroll up, it reappears for easy navigation access. This guide walks through setting up and creating auto-hiding navigation using React Headroom with React, from installation to a working implementation. This is part 46 of a series on using React Headroom with React.
Prerequisites
Before you begin, make sure you have:
- Node.js version 14.0 or higher installed
- npm, yarn, or pnpm package manager
- A React project (version 16.8 or higher) or create-react-app setup
- Basic knowledge of React components
- Familiarity with JavaScript/TypeScript
Installation
Install React Headroom using your preferred package manager:
npm install react-headroom
Or with yarn:
yarn add react-headroom
Or with pnpm:
pnpm add react-headroom
After installation, your package.json should include:
{
"dependencies": {
"react-headroom": "^3.1.0",
"react": "^18.0.0",
"react-dom": "^18.0.0"
}
}
Project Setup
React Headroom requires minimal setup. Import the component and you're ready to use it.
First Example / Basic Usage
Let's create a simple auto-hiding header. Create a new file src/HeadroomExample.jsx:
// src/HeadroomExample.jsx
import React from 'react';
import Headroom from 'react-headroom';
function HeadroomExample() {
return (
<div>
<Headroom>
<header style={{
backgroundColor: '#2c3e50',
color: 'white',
padding: '15px 30px',
boxShadow: '0 2px 4px rgba(0,0,0,0.1)'
}}>
<h1 style={{ margin: 0, fontSize: '24px' }}>My Website</h1>
</header>
</Headroom>
<div style={{ padding: '40px', minHeight: '200vh' }}>
<h2>Scroll down to see the header hide</h2>
<p>Scroll up to see it reappear.</p>
<div style={{ height: '1500px', backgroundColor: '#f0f0f0', padding: '20px' }}>
<p>This is a long content area to demonstrate the headroom effect.</p>
<p>Keep scrolling down...</p>
<p>And scrolling...</p>
<p>The header will hide when you scroll down.</p>
<p>Scroll back up to see it appear again.</p>
</div>
</div>
</div>
);
}
export default HeadroomExample;
Update your App.jsx:
// src/App.jsx
import React from 'react';
import HeadroomExample from './HeadroomExample';
import './App.css';
function App() {
return (
<div className="App">
<HeadroomExample />
</div>
);
}
export default App;
This creates a header that automatically hides when scrolling down and reappears when scrolling up.
Understanding the Basics
React Headroom provides several key features:
- Headroom component: Wraps your header to enable auto-hide functionality
- Automatic detection: Detects scroll direction and hides/shows accordingly
- Smooth animations: Smooth transitions when hiding and showing
- Customization: Configurable thresholds and animation options
- Zero configuration: Works out of the box with sensible defaults
Key concepts:
- Scroll Detection: Headroom monitors scroll events to determine direction
- Hide on Scroll Down: Header hides when user scrolls down
- Show on Scroll Up: Header reappears when user scrolls up
- Smooth Transitions: Uses CSS transitions for smooth animations
- Threshold: Configurable scroll distance before hiding/showing
Here's an example with a navigation menu:
// src/NavigationHeadroom.jsx
import React from 'react';
import Headroom from 'react-headroom';
function NavigationHeadroom() {
const navItems = ['Home', 'About', 'Services', 'Contact'];
return (
<div>
<Headroom>
<nav style={{
backgroundColor: '#007bff',
color: 'white',
padding: '15px 30px',
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
boxShadow: '0 2px 4px rgba(0,0,0,0.1)'
}}>
<div style={{ fontSize: '20px', fontWeight: 'bold' }}>
Logo
</div>
<div style={{ display: 'flex', gap: '20px' }}>
{navItems.map(item => (
<a
key={item}
href={`#${item.toLowerCase()}`}
style={{
color: 'white',
textDecoration: 'none',
padding: '5px 10px',
borderRadius: '4px',
transition: 'background-color 0.3s'
}}
onMouseEnter={(e) => e.target.style.backgroundColor = 'rgba(255,255,255,0.2)'}
onMouseLeave={(e) => e.target.style.backgroundColor = 'transparent'}
>
{item}
</a>
))}
</div>
</nav>
</Headroom>
<div style={{ padding: '40px', minHeight: '200vh' }}>
<h2>Navigation with Headroom</h2>
<p>Scroll down to see the navigation hide.</p>
<div style={{ height: '1500px', backgroundColor: '#f8f9fa', padding: '20px' }}>
<p>Long content area...</p>
</div>
</div>
</div>
);
}
export default NavigationHeadroom;
Practical Example / Building Something Real
Let's build a complete website layout with an auto-hiding header:
// src/WebsiteWithHeadroom.jsx
import React from 'react';
import Headroom from 'react-headroom';
function WebsiteWithHeadroom() {
const menuItems = [
{ id: 1, label: 'Home', href: '#home' },
{ id: 2, label: 'About', href: '#about' },
{ id: 3, label: 'Services', href: '#services' },
{ id: 4, label: 'Portfolio', href: '#portfolio' },
{ id: 5, label: 'Contact', href: '#contact' }
];
return (
<div>
<Headroom
style={{
zIndex: 1000
}}
pinStart={64}
upTolerance={10}
downTolerance={10}
>
<header style={{
backgroundColor: '#ffffff',
boxShadow: '0 2px 8px rgba(0,0,0,0.1)',
padding: '15px 30px',
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center'
}}>
<div style={{
fontSize: '24px',
fontWeight: 'bold',
color: '#2c3e50'
}}>
MyApp
</div>
<nav style={{ display: 'flex', gap: '30px', alignItems: 'center' }}>
{menuItems.map(item => (
<a
key={item.id}
href={item.href}
style={{
color: '#2c3e50',
textDecoration: 'none',
padding: '8px 15px',
borderRadius: '4px',
transition: 'all 0.3s',
fontWeight: '500'
}}
onMouseEnter={(e) => {
e.target.style.backgroundColor = '#f8f9fa';
e.target.style.color = '#007bff';
}}
onMouseLeave={(e) => {
e.target.style.backgroundColor = 'transparent';
e.target.style.color = '#2c3e50';
}}
>
{item.label}
</a>
))}
<button
style={{
padding: '10px 20px',
backgroundColor: '#007bff',
color: 'white',
border: 'none',
borderRadius: '4px',
cursor: 'pointer',
fontWeight: '500',
transition: 'background-color 0.3s'
}}
onMouseEnter={(e) => e.target.style.backgroundColor = '#0056b3'}
onMouseLeave={(e) => e.target.style.backgroundColor = '#007bff'}
>
Get Started
</button>
</nav>
</header>
</Headroom>
<main>
<section id="home" style={{
padding: '100px 40px',
textAlign: 'center',
backgroundColor: '#f8f9fa',
minHeight: '100vh'
}}>
<h1 style={{ fontSize: '48px', marginBottom: '20px' }}>Welcome to MyApp</h1>
<p style={{ fontSize: '20px', color: '#666', marginBottom: '30px' }}>
Scroll down to see the header automatically hide
</p>
</section>
<section id="about" style={{
padding: '80px 40px',
backgroundColor: 'white',
minHeight: '100vh'
}}>
<h2 style={{ fontSize: '36px', marginBottom: '20px' }}>About Us</h2>
<p style={{ fontSize: '18px', lineHeight: '1.6', color: '#666' }}>
This is the about section. The header will hide when you scroll down
and reappear when you scroll up, providing a better user experience
by maximizing screen space while keeping navigation accessible.
</p>
</section>
<section id="services" style={{
padding: '80px 40px',
backgroundColor: '#f8f9fa',
minHeight: '100vh'
}}>
<h2 style={{ fontSize: '36px', marginBottom: '20px' }}>Our Services</h2>
<p style={{ fontSize: '18px', lineHeight: '1.6', color: '#666' }}>
Service content goes here. Keep scrolling to see the headroom effect in action.
</p>
</section>
<section id="portfolio" style={{
padding: '80px 40px',
backgroundColor: 'white',
minHeight: '100vh'
}}>
<h2 style={{ fontSize: '36px', marginBottom: '20px' }}>Portfolio</h2>
<p style={{ fontSize: '18px', lineHeight: '1.6', color: '#666' }}>
Portfolio content goes here.
</p>
</section>
<section id="contact" style={{
padding: '80px 40px',
backgroundColor: '#f8f9fa',
minHeight: '100vh'
}}>
<h2 style={{ fontSize: '36px', marginBottom: '20px' }}>Contact Us</h2>
<p style={{ fontSize: '18px', lineHeight: '1.6', color: '#666' }}>
Contact information goes here.
</p>
</section>
</main>
</div>
);
}
export default WebsiteWithHeadroom;
Now create a blog layout with headroom:
// src/BlogWithHeadroom.jsx
import React from 'react';
import Headroom from 'react-headroom';
function BlogWithHeadroom() {
const blogPosts = Array.from({ length: 10 }, (_, i) => ({
id: i + 1,
title: `Blog Post ${i + 1}`,
excerpt: `This is the excerpt for blog post ${i + 1}. It contains some sample text to demonstrate the headroom effect.`
}));
return (
<div>
<Headroom
style={{
zIndex: 1000
}}
>
<header style={{
backgroundColor: '#2c3e50',
color: 'white',
padding: '15px 30px',
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
boxShadow: '0 2px 4px rgba(0,0,0,0.1)'
}}>
<div style={{ fontSize: '24px', fontWeight: 'bold' }}>
My Blog
</div>
<nav style={{ display: 'flex', gap: '20px' }}>
<a href="#home" style={{ color: 'white', textDecoration: 'none' }}>Home</a>
<a href="#posts" style={{ color: 'white', textDecoration: 'none' }}>Posts</a>
<a href="#about" style={{ color: 'white', textDecoration: 'none' }}>About</a>
</nav>
</header>
</Headroom>
<main style={{ padding: '40px', maxWidth: '800px', margin: '0 auto' }}>
<h1 style={{ marginBottom: '30px' }}>Blog Posts</h1>
{blogPosts.map(post => (
<article
key={post.id}
style={{
marginBottom: '40px',
padding: '20px',
backgroundColor: '#f8f9fa',
borderRadius: '8px',
boxShadow: '0 2px 4px rgba(0,0,0,0.1)'
}}
>
<h2 style={{ marginBottom: '10px' }}>{post.title}</h2>
<p style={{ color: '#666', lineHeight: '1.6' }}>{post.excerpt}</p>
</article>
))}
</main>
</div>
);
}
export default BlogWithHeadroom;
Update your App.jsx:
// src/App.jsx
import React from 'react';
import WebsiteWithHeadroom from './WebsiteWithHeadroom';
import './App.css';
function App() {
return (
<div className="App">
<WebsiteWithHeadroom />
</div>
);
}
export default App;
This example demonstrates:
- Auto-hiding navigation header
- Smooth hide/show animations
- Customizable scroll thresholds
- Full website layout
- Blog layout with headroom
- Responsive navigation
Common Issues / Troubleshooting
Header not hiding: Make sure the content is scrollable. If the page content is shorter than the viewport, there's nothing to scroll and the header won't hide. Add enough content to enable scrolling.
Header hiding too quickly: Adjust the
downToleranceprop to increase the scroll distance before hiding. Higher values require more scrolling before the header hides.Header not reappearing: Check the
upToleranceprop. This controls how much you need to scroll up before the header reappears. Lower values make it reappear sooner.Z-index issues: If the header appears behind other elements, set a higher
zIndexin the Headroom component's style prop.Animation not smooth: React Headroom uses CSS transitions by default. If animations seem choppy, check for CSS conflicts or performance issues.
Header not pinning at top: Use the
pinStartprop to control when the header should start pinning. This is useful if you have content above the header that should scroll normally first.
Next Steps
Now that you have a basic understanding of React Headroom:
- Learn about advanced configuration options
- Explore different animation styles
- Implement custom scroll thresholds
- Add header state callbacks
- Integrate with React Router for navigation
- Learn about other sticky header libraries
- Check the official repository: https://github.com/KyleAMathews/react-headroom
- Look for part 47 of this series for more advanced topics
Summary
You've successfully set up React Headroom in your React application and created auto-hiding navigation headers that improve user experience by maximizing content space while keeping navigation accessible. React Headroom provides a simple solution for creating headers that automatically hide and show based on scroll direction.
SEO Keywords
react-headroom
React auto-hiding header
react-headroom tutorial
React sticky navigation
react-headroom installation
React scroll header
react-headroom example
React hide on scroll
react-headroom setup
React navigation header
react-headroom customization
React scroll detection
react-headroom animations
React header library
react-headroom getting started
Top comments (0)