reactjstypescriptconditional-statementstailwind-cssnavbar

React how to set active link text color using dynamic conditions


I am trying to build a dynamic nav bar which has 2 states one for when you are on the HomePage and have not yet scrolled and a 2nd for when you scroll down on the HomePage or are on any other page.

I got all the links to update to the right colour expect for the HomePage link will not be black when not on the HomePage.

import { useState, useEffect } from 'react'
import { NavLink, useLocation  } from 'react-router-dom'
import { RxHamburgerMenu } from "react-icons/rx";
import { FaTimes } from "react-icons/fa";
import { getImageURL } from '@/utils/image-utils'


function Navbar() {
 
  //  Nav is starting off false
  const [nav, setNav] = useState(false)
  // When user clicks Hamburger buttom, it gomes from false(!nav) to true(nav)
  const handleClick = () => setNav(!nav)
  // navBg is set to false on load as the user has not yet scrolled
  const [navBg, setNavBg] = useState(false);

  // Gets the current location of the route
  const location = useLocation()
  // sets isHome to true if user is at root
  const isHome = location.pathname === '/' ? true : false;

  // Toggles the navbg state if scrolled over 300 and back to false if otherwise
  const changeNavBg = () => {
    window.scrollY >= 300 ? setNavBg(true) : setNavBg(false);
  }

  // Monitors user scrolling and triggers check
  useEffect(() => {
    window.addEventListener('scroll', changeNavBg);
    return () => {
      window.removeEventListener('scroll', changeNavBg);
    }
  }, [])
  
  return (
      <nav className={`${isHome && navBg ? 'bg-white': 'bg-blue-500'} sticky top-0 z-50 xs:p-6 sm:p-6 md:p-6 lg:p-0 xl:p-0 ${!isHome ? 'bg-white': '' }`}>
      <div className="container mx-auto flex flex-wrap items-center justify-between ">
        <NavLink to="/" className="inline-block mr-4 py-0.5 text-xl whitespace-nowrap hover:no-underline focus:no-underline "><img src={`${isHome && !navBg ? getImageURL("logo-white.svg") : getImageURL("logo-blue.svg")}`}alt="" width="200" className='h-15'/></NavLink>

          {/* Hamburger or Close Icon */}
          
          <div className='lg:hidden z-10 ' onClick={handleClick}>
            { nav ? <FaTimes size={25} color='black'/> : <RxHamburgerMenu size ={25}/>}
            <ul className={`${
              nav 
              ? 'text-white opacity-100 transform translate-x-0'
              : 'opacity-0 transform -translate-y-full'} transition-transform absolute top-20 w-full h-screen left-0 flex flex-col justify-center items-center bg-black text-2xl
              `}>
              <NavLink to='/'><li className='p-2 hover:text-blue-500'>Home</li></NavLink>
              <NavLink to='/services/'><li className='p-2 hover:text-blue-500'>Services</li></NavLink>
              <NavLink to='/solutions/'><li className='p-2 hover:text-blue-500'>Solutions</li></NavLink>
              <NavLink to='/demos/'><li className='p-2 hover:text-blue-500'>Demos</li></NavLink>     
              <NavLink to='/about/'><li className='p-2 hover:text-blue-500'>About Us</li></NavLink>        
              <NavLink to='/contactus/'><li className='p-2 hover:text-blue-500'>Contact Us</li></NavLink>
            </ul>
          </div>
            
        <div className="hidden w-full lg:flex lg:w-auto lg:order-1" >  
          <ul className="flex flex-row justify-between space-x-6 p-4 mt-4 font-medium items-center align-middle ">
          <li>
            <NavLink to="/" className={`${isHome && !navBg? 'text-white':'text-blue-500'} ${!isHome ? 'text-black':''}`}>Home</NavLink>
          </li>
          <li>
            <NavLink to="/services/" className={`${location.pathname.includes('/services/') ? 'text-blue-500':'text-black'}`}>Services</NavLink>
          </li>
          <li>
            <NavLink to="/solutions/" className={`${location.pathname.includes('/solutions/') ? 'text-blue-500':'text-black'}`}>Solutions</NavLink>
          </li>
          <li>
            <NavLink to="/demos/" className={`${location.pathname.includes('/demos/') ? 'text-blue-500':'text-black'}`}>Demos</NavLink>
          </li>
          <li>
            <NavLink to="/about/" className={`${location.pathname.includes('/about/') ? 'text-blue-500':'text-black'}`}>About Us</NavLink>
          </li>
          <li>
            <NavLink to="/contactus/"><button type="button" className="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-4 py-2 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800">Contact Us</button></NavLink>          
          </li>
            
          </ul> 
        </div>
  
      </div>
    
    </nav>
    

  )
}

export default Navbar

The only link not working is the item below, the first conditions work fine if we are on the HomePage and have not scrolled it sets the text colours to white and when we do scrolled it updates to blue. However if we are not on the the HomePage it does not trigger and change the text to black.

<NavLink to="/" className={${isHome && navBg? 'text-blue-500':'text-white'} ${!isHome ? 'text-black':''}}>Home</NavLink>

I based the logic on the logic i used for the background colours for the Navbar which works as expected.

<nav className={${isHome && navBg ? 'bg-white': 'bg-blue-500'} sticky top-0 z-50 xs:p-6 sm:p-6 md:p-6 lg:p-0 xl:p-0 ${!isHome ? 'bg-white': '' }}>


Solution

  • The issue is in your conditional logic for the Home link. The logic will be

    1. First check if we're on HomePage(isHome)
    2. if we are on Homepage show blue text if scrolled(navBg is grue) and show white text if not scrolled(navBg is false)
    3. if we're not on Homepage, show black text

    <NavLink to="/" className={${isHome ? (navBg ? 'text-blue-500' : 'text-white') : 'text-black'}}>Home