0

When I click the hamburger menu button I want both .menu-btn .menu-mob the menu button and the navigation menu the have to is-active class and .sqr to have the class .hidden when the other two are active. That's why I used toggle() to toggle all these classes, but for some reason it is not working.

Link to all code in repo

Note that I'm using react and tailwind and some vanilla css

const showNav = () => {
    const menuBtn = document.querySelector('.menu-btn')
    const navbar = document.querySelector('.menumob')
    const sqr = document.querySelector('.sqr')

    menuBtn.addEventListener('click', () => {
      menuBtn.classList.toggle('is-active')
      navbar.classList.toggle('is-active')
      sqr.classList.toggle('hidden')
    })
 <button class="menu-btn hamburger  absolute top-0 right-0 md:hidden" onClick={showNav()}>
            <div class="bar"></div>
 </button>
 .hamburger.is-active::before {
    transform: rotate(-45deg) translate(-8px, 6px);
 }

 .hamburger.is-active::after {
    transform: rotate(45deg) translate(-9px, -8px);
 }

 .hamburger.is-active .bar {
    opacity: 0;
 }


 .menumob {
    position: relative;
    top:0;
    left:100%;
    transition: 0.4s;
 }

 .menumob.is-active {
    left:0;
 }
Sam Rad
  • 71
  • 8
  • If you click the hamburger menu twice, does it work? – nevada_scout Dec 31 '22 at 16:02
  • @nevada_scout yes it but i does not go as I want it to. the menu suppose to be displayed and at the same time the element with the class sqr should be hidden. – Sam Rad Dec 31 '22 at 16:21
  • If you're using react why are you manually adding click listeners? (and apparently never cleaning them up) – pilchard Dec 31 '22 at 16:26
  • @pilchard yeah, it's because I'm new to react. Still making so many mistakes :') – Sam Rad Dec 31 '22 at 16:30
  • duplicate: [React Js conditionally applying class attributes](https://stackoverflow.com/questions/30533171/react-js-conditionally-applying-class-attributes) – pilchard Dec 31 '22 at 17:55

2 Answers2

1

Given that you are using React you should be leveraging React's DOM handling rather than manually manipulating it yourself. For your specific situation all you need is a single boolean state storing whether the menu is active or not and then using that variable you can conditionally include the relevant styles, or even conditionally render elements instead of hiding them.

const Nav = () => {
  const [isActive, setIsActive] = React.useState(false);

  const toggleNav = () => {
    setIsActive(isActive => !isActive);
  };

  return (
    <nav className='flex flex-col justify-center h-screen md:h-screen md:mb-36 max-md:relative'>
      {/* MOBILE MENU */}
      <div
        className={'menumob container flex flex-col justify-center bg-black text-white h-screen w-screen md:hidden'
          + (isActive
            ? ' is-active'
            : '')}
      >
      </div>

      {/* Humberguer Menu */}
      <button
        className={'menu-btn hamburger  absolute top-0 right-0 md:hidden'
          + (isActive
            ? ' is-active'
            : '')}
        onClick={() => showNav()}
      >
        <div class='bar'></div>
      </button>

      {/* Imerses experiences */}
      {/* conditionall rendering with AND short-circuit */}
      {!isActive
        && (
          <div className='sqr container mx-auto my-0 top-1/2 mt-10 xl:px-56 max-md:absolute max-md:top-1/3'>
          </div>
        )}
    </nav>
  );
};

see related question: React Js conditionally applying class attributes

and the documentation:

pilchard
  • 12,414
  • 5
  • 11
  • 23
0

It's a bad idea to set up an event listener inside an onclick event. Every time you click, a new listener will be created causing the code to fire multiple times on each click.

In your code, the first time you click the event listener will be created but the code inside the listener won't run. The second time you click, the code inside the listener should run, but another listener will be created. The third time you click, the code inside the listener will run twice (toggling the class twice), and adding another listener. (And repeat for each click.)

The event listener is not needed at all, because the showNav function only runs when the hamburger menu item is clicked - because of onClick={showNav()} in the HTML. Try changing the code to this and see if it works:

const showNav = () => {
  const menuBtns = document.querySelector('.menu-btn')
  const navbars = document.querySelector('.menumob')
  const sqrs = document.querySelector('.sqr')

  menuBtn.classList.toggle('is-active')
  navbar.classList.toggle('is-active')
  sqr.classList.toggle('hidden')
};

Also, note that document.querySelector returns only the first matching element, so if you have more than one element with the class .menu-btn, .menumob or .sqr then not all of them will be updated.

nevada_scout
  • 971
  • 3
  • 16
  • 37
  • after I tried your answer, the mobile menu no longer shows up, this time whenever I click only the button that works but nothing else. – Sam Rad Dec 31 '22 at 16:18
  • 1
    update : I think it's started working after I have added your code and also changed ```onClick={showNav()}``` to ```onClick={() => showNav()}``` – Sam Rad Dec 31 '22 at 16:26