Change Navbar Background Color on Scroll
Tiny changes make remarkable result in a web page.
Changing the background color of a navbar when you scroll can add more beauty to the website and improve user experience.
Follow along as we implement this simple effect as you scroll the webpage.
Prerequisite
Basic understanding of HTML, CSS, JavaScript.
Tailwind CSS and React or Next.js.
Step 1: Setup
I will be using a Next.js app for this, but you can use React also.
Create a Navbar component in your React or Next.js app. I am using the app/page.js file.
import React from "react"
export default function Navbar() {
return (
<nav className="">
</nav>
)};
Step 2: Creating Navbar
You need to create the navbar with the nav element and style it with Tailwind CSS
import React from "react";
export default function Navbar() {
return (
<nav className="w-full top-0 fixed z-40">
<div className="p-4 bg-zinc-100">
<div className="flex items-center justify-between">
<div className="text-lg font-semibold">Navbar</div>
</div>
</div>
</nav>
);
}
The navbar shows on the page now.
Let's add state now.
Step 3: Adding State
"use client"
import React, { useState } from "react"
export default function Navbar(){
const [showBackground, setShowBackground] = useState(false)
return (
<nav className="w-full top-0 fixed z-40">
<div className="p-4 bg-zinc-100">
<div className="flex items-center justify-between">
<div className="text-lg font-semibold">Navbar</div>
</div>
</div>
</nav>
);
}
"use client"
was added at the top to make the useState()
hook work. All Next.js components are on the server side, so they do not have access to client side event handlers or React hooks like useState()
. The "use client"
turns the component to a client-side component. Read more about how that works here.
const [showBackground, setShowBackground] = useState(false)
The above code sets showBackground
to false. This will be used to change the navbar background color when showBackground
changes to true.
Let's track the scroll position now.
Step 4: Track Scroll Position
Create a variable to store the top offset.
const TOP_OFFSET = 50;
This constant defines the scroll offset (in pixels).
You need to create a logic to set showBackground
to true when the scroll offset is reached.
Here is the logic implemented by the useEffect()
hook.
useEffect(() => {
const handleScroll = () => {
if (window.scrollY >= TOP_OFFSET) {
setShowBackground(true)
} else {
setShowBackground(false)
}
}
window.addEventListener('scroll', handleScroll);
return () => {
window.removeEventListener('scroll', handleScroll);
}
}, []);
When the scroll position exceeds a TOP_OFFSET
, that is when the user has scrolled down by at least 50 pixels, showBackground
will be set to true
.
Event listeners are also added.
window.addEventListener('scroll', handleScroll);
return () => {
window.removeEventListener('scroll', handleScroll);
};
The above code add event listeners in the useEffect()
hook to call the handleScroll
function when you scroll, it also returns a cleanup function that removes the event listener when the component is unmounted to avoid memory leaks.
Here is the whole code now.
"use client"
import React, { useState, useEffect } from "react"
export default function Navbar() {
const TOP_OFFSET = 50;
const [showBackground, setShowBackground] = useState(false)
useEffect(() => {
const handleScroll = () => {
console.log(window.scrollY)
if (window.scrollY >= TOP_OFFSET) {
setShowBackground(true)
} else {
setShowBackground(false)
}
}
window.addEventListener('scroll', handleScroll);
return () => {
window.removeEventListener('scroll', handleScroll);
}
}, []);
return (
<nav className="w-full top-0 fixed z-40">
<div className="p-4 bg-zinc-100">
<div className="flex items-center justify-between">
<div className="text-lg font-semibold">Navbar</div>
</div>
</div>
</nav>
);
}
Let's make the nav element interact with showBackground
state to make it dynamic and react to the scroll effects.
Step 5: Make Navbar Element Dynamic
return (
<nav className="w-full top-0 fixed z-40">
<div className={`p-4 ${showBackground ? "bg-gray-800" : "bg-zinc-100"}`}>
<div className="flex items-center justify-between">
<div className={`text-lg font-semibold ${showBackground ? "text-white" : ""}`}>
Navbar
</div>
</div>
</div>
</nav>
)};
If showBackground
is true
the direct div child of nav element has a "bg-gray-800" class name
the Navbar text's div has a class name of "text-white".
If showBackground
is false
the direct div child of nav element has a "bg-zinc-100" class name
the Navbar text's div removes the "text-white" class name.
Here is the whole code now.
"use client";
import React, { useState, useEffect } from "react";
export default function Navbar() {
const TOP_OFFSET = 50;
const [showBackground, setShowBackground] = useState(false);
useEffect(() => {
const handleScroll = () => {
console.log(window.scrollY);
if (window.scrollY >= TOP_OFFSET) {
setShowBackground(true);
} else {
setShowBackground(false);
}
};
window.addEventListener("scroll", handleScroll);
return () => {
window.removeEventListener("scroll", handleScroll);
};
}, []);
return (
<nav className="w-full top-0 fixed z-40">
<div className={`p-4 ${showBackground ? "bg-gray-800" : "bg-zinc-100"}`}>
<div className="flex items-center justify-between">
<div
className={`text-lg font-semibold ${
showBackground ? "text-white" : ""
}`}
>
Navbar
</div>
</div>
</div>
</nav>
);
}
Step 6: Testing
To test the scroll effect, add content after the div that makes the whole window height higher than the window viewport, so that the scrollbar will be visible.
return (
<>
<nav className="w-full top-0 fixed z-40">
<div className={`p-4 ${showBackground ? "bg-gray-800" : "bg-zinc-100"}`}>
<div className="flex items-center justify-between">
<div className={`text-lg font-semibold ${showBackground ? "text-white" : ""}`}>
Navbar
</div>
</div>
</div>
</nav>
<div className="mt-[90vh]">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
commodo consequat. Duis aute irure dolor in reprehenderit in voluptate
velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint
occaecat cupidatat non proident, sunt in culpa qui officia deserunt
mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur
adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore
magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco
laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa
qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit
amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut
labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud
exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum
dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</div>
</>
);
}
You can now scroll down to see the effects.
Conclusion
When you scroll down with the top offset getting to 50px, it sets showBackground
to true and thus changes the background of the nav div, same goes for the color of the "Navbar" text.
Here is the GitHub repo to copy this code. Click here to clone it.
That will be all. Hope you found any value here as you learn to build more projects effectively.
Before you leave,
If you enjoyed this article and want to see more content related to JavaScript and Web development, then follow me here, Twitter (X) or connect on LinkedIn.
I'd be happy to count you as one of my ever-growing group of awesome friends on the internet.
If you also want to support me, you can buy a cup of coffee for me here.
Thanks && Bye. ๐
Subscribe to my newsletter
Read articles from Segun Ajibola directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Segun Ajibola
Segun Ajibola
I'm a front-end web developer, enjoys working with TailwindCSS and React. Love to contribute to Open Source and meet new people on Twitter.