React - Top Nav Hide on Scroll
Overview
Estimated time: 15–25 minutes
Implement a top navigation bar that hides on scroll down and reappears on scroll up, with minimal reflows.
Try it: Hide on scroll
View source
function useScrollDir(){
const [dir, setDir] = React.useState('up');
const last = React.useRef(window.scrollY);
React.useEffect(() => {
let ticking = false;
function onScroll(){
if (!ticking){
window.requestAnimationFrame(() => {
const y = window.scrollY;
const d = y > last.current ? 'down' : 'up';
if (Math.abs(y - last.current) > 4) setDir(d);
last.current = y;
ticking = false;
});
ticking = true;
}
}
window.addEventListener('scroll', onScroll, {passive:true});
return () => window.removeEventListener('scroll', onScroll);
}, []);
return dir;
}
function App(){
const dir = useScrollDir();
return (
<div>
<header style={{position:'sticky', top:0, transition:'transform .2s', transform: dir==='down'? 'translateY(-100%)' : 'translateY(0)', background:'var(--bg)', borderBottom:'1px solid var(--border)', padding:'8px 12px', zIndex:10}}>
<strong>My App</strong> <span style={{opacity:.6}}>Top bar hides on scroll</span>
</header>
<main style={{height:480, overflow:'auto'}}>
{[...Array(20)].map((_,i)=> <p key={i}>Content line {i+1} lorem ipsum dolor sit amet...</p>)}
</main>
</div>
);
}
ReactDOM.createRoot(document.getElementById('try-topnav')).render(<App />);
Syntax primer
- Use requestAnimationFrame to throttle scroll handling.
- Position: sticky keeps the header in flow but pinned to the top.
Common pitfalls
- Using heavy onScroll logic—prefer throttling or rAF to avoid jank.
Exercises
- Only hide after a threshold (e.g., 64px scrolled) and reveal near top.