Hello World!
Let me show you how we can create a header that shrinks when we scroll down and expands when we scroll back to the top in React.
We can listen to the scroll using the event listeners. We will have to start listening to the scroll when the component mounts and will have to stop listening when the component unmounts. For this, we can make use of the useEffect
hooks.
useEffect(() => {
// Adding the scroll listener
window.addEventListener('scroll', handleScroll, { passive: true });
return () => {
// Removing listener
window.removeEventListener('scroll', handleScroll);
};
}, []);
passive
is used to denote that an event is a passive event and the handler won't call the preventDefault
to disable scrolling.
To know whether the page is scrolled or not, we can use a flag called isScrolled
. The isScrolled
is to be set to true
, when the screen is scrolled beyond a point (250, for example) and set to false
when scrolled back to the top (when the scroll position is less than 250). We can track the scroll position with window.pageYOffset
.
So the handler function would be:
// Flag, which stores whether the screen is scrolled
const [isScrolled, setScrolled] = useState(false);
// Handler when page is scrolled
const handleScroll = () => {
if(window.pageYOffset > 250) {
setScrolled(true)
} else {
setScrolled(false)
}
}
Now, we can sense whether the page is scrolled or not using the isScrolled
flag. Now we can implement the header component markup like:
return (
<div className={`header-container ${isScrolled && 'header-scrolled'}`}>
<h1>SR</h1>
<h2>Sriram</h2>
</div>
);
Here, we are injecting the header-scrolled
class when the screen is scrolled. That is when the isScrolled
is true.
Let us see the styling of the component:
.header-container {
display: flex;
align-items: center;
background: $header-color;
box-shadow: rgba(0, 0, 0, 0.2) 0px 12px 28px 0px, rgba(0, 0, 0, 0.1) 0px 2px 4px 0px, rgba(255, 255, 255, 0.05) 0px 0px 0px 1px inset;
height: 7rem;
}
.header-scrolled {
height: 3rem;
}
Here in the header-container
class, the height is set to 7rem
. When the page is scrolled and header-scrolled
class is injected, the height would be replaced with 3rem
, which would shrink the header vertically.
But the grow/shrink transition would be sharp now. We can add some transition
in the CSS to make the grow/shrink smooth.
.header-container {
display: flex;
align-items: center;
background: $header-color;
box-shadow: rgba(0, 0, 0, 0.2) 0px 12px 28px 0px, rgba(0, 0, 0, 0.1) 0px 2px 4px 0px, rgba(255, 255, 255, 0.05) 0px 0px 0px 1px inset;
height: 7rem;
// To make the grow/shrink smooth.
transition: height 2s;
}
That's it, we are done! Now, when we scroll the screen, the header will grow and shrink smoothly.
The final code would be:
import React, { useEffect, useState } from "react";
import "./header.scss";
export default function Header() {
const [isScrolled, setScrolled] = useState(false);
useEffect(() => {
window.addEventListener('scroll', handleScroll, { passive: true });
return () => {
window.removeEventListener('scroll', handleScroll);
};
}, []);
const handleScroll = () => {
if(window.pageYOffset > 250) {
setScrolled(true)
} else {
setScrolled(false)
}
}
return (
<div className={`header-container ${isScrolled && 'header-scrolled'}`}>
<h1>SR</h1>
<h2>Sriram</h2>
</div>
);
}
.header-container {
display: flex;
align-items: center;
background: $header-color;
box-shadow: rgba(0, 0, 0, 0.2) 0px 12px 28px 0px, rgba(0, 0, 0, 0.1) 0px 2px 4px 0px, rgba(255, 255, 255, 0.05) 0px 0px 0px 1px inset;
height: 7rem;
transition: height 2s;
}
.header-scrolled {
height: 3rem;
}
Hope this is helpful to you. I am looking forward to your feedback; thank you!
Also published here.