skip to Main Content

I’m trying to create a navigation bar that is supposed to be transparent when the user is scrolled all the way to the top. When the user scrolls down from the top, the navigation bar changes background and text color so that the bar is visible. In my React project, I’m using TailwindCSS for almost all of my styling. My code works, I know that for a fact.

// src/components/Navbar.js
import React, { useState } from 'react';

const Navbar = () => {
  const [navbarBackground, setNavbarBackground] = useState('transparent');
  const [navbarTextColor, setNavbarTextColor] = useState('slate-200');

  const handleScroll = () => {
    const scrolled = window.scrollY;
    if (scrolled > 20) {
      setNavbarBackground('slate-200');
      setNavbarTextColor('slate-800');
    } else {
      setNavbarBackground('transparent');
      setNavbarTextColor('slate-200');
    }
  };

  window.addEventListener('scroll', handleScroll);

  return (
    <nav 
      className={`flex justify-between p-4 fixed top-0 w-full z-50 transition bg-${navbarBackground}`}
    >
      <div className={`font-cursive text-${navbarTextColor}`}>Luca Cangelosi</div>
      <div className="flex space-x-10">
        <a className={`text-${navbarTextColor} font-semibold transition cursor-pointer`}>About</a>
        <a className={`text-${navbarTextColor} font-semibold transition cursor-pointer`}>Store</a>
        <a className={`text-${navbarTextColor} font-semibold transition cursor-pointer`}>Contact</a>

        <div>
          <i className={`text-${navbarTextColor} fas fa-shopping-cart transition cursor-pointer`}></i>
        </div>
      </div>
    </nav>
  );
};

export default Navbar;

All the code above does is, when the user scrolls, it checks the Y-position of the window. If the position is 0 (the user is at the top of the page), then the class on the navbar is bg-transparent and the text color of the links are text-slate-200. Otherwise, the class on the navbar is bg-slate-200 and the link colors are text-slate-800.

However, for some reason, when I first run npm start, the code doesn’t seem to work. In fact, the background of the navigation bar is transparent (even after I scroll down), and the color of the links are either black or slate-800 (I can’t tell). Scrolling doesn’t change anything. However, when I set one of the links to always be slate-800, or something similar, everything else seems to work fine. After that, I changed it back to be based off the scrolling, and it worked fine.

Basically, it didn’t work until I hard-set one of the colors to be permanently one color (not based off the scrolling), and then everything worked (background and link colors). Then, when I change it back to the original code, it continues to work.

Why does this happen? Why doesn’t it work the first time. I’m afraid that in production, this would be the case. How would I fix it?

Thanks!

2

Answers


  1. I think you can try to use boolean for the state value. It’s more readable.

    const [navbarBackground, setNavbarBackground] = useState(false);
    const [navbarTextColor, setNavbarTextColor] = useState(false);
    

    If you don’t use addEventListener inside useEffect, and instead use it directly in the component body, it can cause the event listener to be added multiple times.

    By using addEventListener inside useEffect, we ensure that the event listener is only added once.

    useEffect(() => {
        const handleScroll = () => {
          const scrolled = window.scrollY;
          if (scrolled > 20) {
            setNavbarBackground(true);
            setNavbarTextColor(true);
          } else {
            setNavbarBackground(false);
            setNavbarTextColor(false);
          }
        };
        window.addEventListener('scroll', handleScroll);
        return () => {
          window.removeEventListener('scroll', handleScroll);
        };
      }, []);
    

    Finally, you can toggle the class name like this.

    className={`flex justify-between p-4 fixed top-0 w-full z-50 transition ${navbarBackground ? 'bg-slate-200' : 'bg-transparent'}`}
    
    Login or Signup to reply.
  2. You must add your full className inside the useState hook.

    slate-400

    text-slate-400 Or bg-slate-400

    When you do slate-400 tailwindcss is not generate the classNames for your component because this thing is not applicable for tailwindcss (According to Docs).

    Now your code should be:

    import { useState, useEffect } from 'react';
    
    const Navbar = () => {
      useEffect(() => {
        window.addEventListener('scroll', () => {
          if (window.scrollY > 20) {
            setNavbarBackground('bg-slate-200');
            setNavbarTextColor('text-slate-800');
          } else {
            setNavbarBackground('bg-transparent');
            setNavbarTextColor('text-slate-200');
          }
        });
      }, []);
      const [navbarBackground, setNavbarBackground] = useState('text-transparent');
      const [navbarTextColor, setNavbarTextColor] = useState('text-slate-200');
    
      return (
        <nav
          className={`flex justify-between p-4 fixed top-0 w-full z-50 transition ${navbarBackground}`}
        >
          <div className={`font-cursive ${navbarTextColor}`}>Luca Cangelosi</div>
          <div className="flex space-x-10">
            <a
              className={`${navbarTextColor} font-semibold transition cursor-pointer`}
            >
              About
            </a>
            <a
              className={`${navbarTextColor} font-semibold transition cursor-pointer`}
            >
              Store
            </a>
            <a
              className={`${navbarTextColor} font-semibold transition cursor-pointer`}
            >
              Contact
            </a>
    
            <div>
              <i
                className={`${navbarTextColor} fas fa-shopping-cart transition cursor-pointer`}
              ></i>
            </div>
          </div>
        </nav>
      );
    };
    export { Navbar };
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search