Change Navbar Background Color on Scroll

Change Navbar Background Color on Scroll

ยท

6 min read

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

  1. Basic understanding of HTML, CSS, JavaScript.

  2. 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. ๐Ÿ‘‹