Search code examples
javascriptreactjsnext.jstailwind-cssresponsive-navigation

Responsive menu not closing when clicked again on menu icon. Next js/React/Tailwind


So im pretty new to next js and react. Im trying to make a responsive navbar bar that closes and opens when clicked on the hamburger icon. (It also closes when clicked outside the opened menu).

The issue here is that it does not seem to be closing again after being clicked on the hamburger icon.. despite what i think is the correct logic being applied.

Any ideas whats going on?

    import { NAV_LINKS } from "@/constants";
    import Image from "next/image";
    import Link from "next/link";
    import { useState, useEffect, useRef } from "react";
    
    
    
    const MobileMenu = () => {
        const [active, setActive] = useState(false);
        const menuRef = useRef<HTMLUListElement>(null);
    
        useEffect(() => {
          const handleClickOutside = (event: MouseEvent) => {
            if (menuRef.current && !(menuRef.current as Node).contains(event.target as Node)) {
                setActive(false);
            }
        };
    
          document.body.addEventListener('click', handleClickOutside);
    
          return () => {
              document.body.removeEventListener('click', handleClickOutside);
          };
        }, []);
    
    
        const handleToggle = () => {
          setActive(prevActive => !prevActive);
        };
      
    
        
     
    
      return (
        <div className='lg:hidden'>
            {/* Hamburger Icon */}
            <div className="cursor-pointer">
                <Image
                  src='/burger-menu.svg'
                  alt='hamburger menu icon'
                  width={34}
                  height={34}
                  onClick={handleToggle}
                  className={active ? 'animateBurger' : ''}
                />
            </div>
            <div className="flex flex-col">
              <ul ref={menuRef} className={active ? 'animateMobileMenu' : 'lg:hidden hidden'}>
                {NAV_LINKS.map((link) => (
                  <Link href={link.href} key={link.key}>
                    {link.label}
                  </Link>
                ))}
              </ul>
            </div>
     
        </div>
      )
    }
    
    export default MobileMenu

Here is the globals.css code as well being used to animated the icon + menu.

  .animateBurger{
    @apply transition rotate-90 opacity-25
  }

  .animateMobileMenu{
    @apply transition-all p-24 flex justify-center items-center flex-col z-50 fixed top-20 left-0 w-full gap-12 text-white-10 regular-16 bg-black-100/75 backdrop-blur-sm
  }


Solution

  • its because your setActive get set two times when click on Hamburger Icon

    1. for handleToggle and second for click outside

    try passing ref to nav bar itself

       <div className='lg:hidden' ref={menuRef}>
            {/* Hamburger Icon */}
            <div  className="cursor-pointer">
                <Image
                  src='/burger-menu.svg'
                  alt='hamburger menu icon'
                  width={34}
                  height={34}
                  onClick={handleToggle}
                  className={active ? 'animateBurger' : ''}
                />
            </div>
            <div className="flex flex-col">
              <ul  className={active ? 'animateMobileMenu' : 'lg:hidden hidden'}>
                {NAV_LINKS.map((link) => (
                  <Link href={link.href} key={link.key}>
                    {link.label}
                  </Link>
                ))}
              </ul>
            </div>
     
        </div>