How to Reveal Sticky Header on Scroll Up
- Published on
- Updated on
If you want to know how to create a sticky header in your react application, this post is for you. In this post, we are going to do that in a pro way as creating a custom hook .
Introduction
On websites, users should see the full content when scrolling down, but they should see the navigation component, that is, the header, when scrolling up. It is very easy to give this experience we just need to know a boolean value whether the user's scroll direction is up or not.
Final Code
Code for the custom hook and the implementation with holy grail layout react application can be found from 👉 here
Custom Hook
import { useEffect, useState } from 'react'
import { off, on } from 'utils'
/**
* useScrollingUp
* @returns {boolean}
*/
const useScrollingUp = () => {
let prevScroll
//if it is SSR then check you are now on the client and window object is available
if (process.browser) {
prevScroll = window.pageYOffset
}
const [scrollingUp, setScrollingUp] = useState(false)
const handleScroll = () => {
const currScroll = window.pageYOffset
const isScrolled = prevScroll > currScroll
setScrollingUp(isScrolled)
prevScroll = currScroll
}
useEffect(() => {
on(window, 'scroll', handleScroll, { passive: true })
return () => {
off(window, 'scroll', handleScroll, { passive: true })
}
}, [])
return scrollingUp
}
export default useScrollingUp
If you are going to use this hook for server side rendering, then window
is not going to be available because our component still not mounted at the client so we can check whether the process is at the client then use window.pageYOffset
; however if you are going to use for client side rendering with react framework then you don't have to worry about the if(process.browser)
check.
As you see, there is a useEffect
we add scroll event listener with a callback function named handleScroll, with some options, i.e. passive:true option. Event listener is attached when the component -which uses this hook- is initially mounted, and the event listener is removed while the component is unmounting. Below you can find a detailed explanation for the variables inside of the useEffect hook:
- prevScroll: We define this variable outside of our callback function as prevScroll which holds vertical pixel value in other words scrolled amount of pixel that is
pageYOffset
or scrollY. It increases with the increasing amount of distance from top to down, in other words scrolled down. - currentScroll: We first define this variable inside of the callback that is the
pageYOffset
value while scrolling event occurs. - 🔊 Attention and repeating : prevScroll is the value when there is no scroll event whereas currentScroll is the current value while scrolling event.
- Therefore when user changes direction to scrolling up, the currentScroll will be less than prevScroll, after comparison we set prevScroll to the currentScroll.
Utils
//exported from src/utils/index.js
export function on(obj, ...args) {
obj.addEventListener(...args)
}
export function off(obj, ...args) {
obj.removeEventListener(...args)
}
Sticky Header
What is we are going to do is, just use useScrolingUp hook and set conditional styles to our header make it sticky while scrolling up.
/**
* Header
* @param {object} children is your menu link items
*/
import useScrollingUp from '@/hooks/useScrollingUp'
const Header = ({ children }) => {
const isScrollingUp = useScrollingUp()
return <header className={`${isScrollingUp ? 'stickyHeader' : ''}`}>{children}</header>
}
export default Header
//App.css or App.scss file
header {
//...the rest is at the source code
box-shadow: none;
border: none;
z-index: 10;
transition: box-shadow 250ms ease-in-out;
//..rest
}
.stickyHeader {
position: fixed;
top: 0;
left: 0;
width: 100%;
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
}
Conclusion
With this post, I want to show that you should not think that react hooks are just solutions for only your application's shared logic or state management, but they also can be used to style our components, or to determine UI component states, i.e. opening a modal, showing a sticky header etc.