Search code examples
javascripthtmlcssnavbarsubmenu

Why does my submenu display one time, then lock up? It also will not close when I click outside of the submenu


I have been trying to solve this problem. The issue is my submenu will display sometimes, and sometimes it won't, so I don't know what is working and what is not. It also will not close when I click out of the submenu, yet the code details that it should. What is happening here? http://jsfiddle.net/jxtzyLk3/1/

let submenu = document.querySelector('.sub-menu')
let submenuHead = document.querySelector('.submenuheader')

openSubmenu = () => {
  if (submenu.style.display === "none") {
    submenu.style.display = "block";
  } else {
    submenu.style.display = "none"
  }
};

submenuHead.addEventListener('click', openSubmenu);
submenu.addEventListener('click', (Event) => {
  Event.stopPropagation();
  window.addEventListener('click', () => {
    if (EventTarget != submenu && submenu.style.display === "block") {
      submenu.style.display = "none";
    }
  });
});
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@200;300;400;500;600;700&display=swap');
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  font-family: 'Poppins', 'Sans-serif';
}

body {
  min-height: 100vh;
}

nav {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 70px;
  background: #333;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
  z-index: 99;
}

nav .navbar {
  height: 100%;
  max-width: 1250px;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin: auto;
  padding: 0 50px;
}

.navbar .logo a {
  font-size: 20px;
  text-decoration: none;
  font-weight: 600;
  color: #ffffff;
}

nav .navbar .nav-links {
  line-height: 70px;
  height: 100%;
}

nav .navbar .links {
  display: flex;
}

nav .navbar .links li {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  list-style: none;
  padding: 0 14px;
}

nav .navbar .links li:hover {
  background-color: #777;
}

nav .navbar .links li a {
  color: #ffffff;
  height: 100%;
  text-decoration: none;
  white-space: nowrap;
  font-size: 15px;
  font-weight: 500;
}

.navbar .links .submenuheader .sub-menu {
  position: absolute;
  top: 70px;
  left: 0;
  line-height: 40px;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
  border-radius: 0 0 4px 4px;
  display: none;
  z-index: 2;
  background: #333;
}
<!DOCTYPE html>

<head>
  <title>Webpage</title>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <html lang="en" dir="ltr" />
  <link rel="stylesheet" href="style.css" />
</head>

<body>
  <nav>
    <div class="navbar">
      <div class="logo"><a href="#">Webpage</a></div>
      <ul class="links">
        <li>
          <a href="#">Home</a>
        </li>
        <li class="submenuheader">
          <a href="#">submenuheader</a>
          <ul class="sub-menu">
            <li><a href="#">Item 1</a></li>
            <li><a href="#">Item 2</a></li>
            <li><a href="#">Item 3</a></li>
          </ul>
        </li>
      </ul>
    </div>
  </nav>
</body>

I have tried switching the JS EventListener for window to document.body. I also tried putting a CSS class .show on .submenu to display the submenu(this did not work well at all with toggling the menu to close when I click out of it.) using this JS:

submenuHeader.onclick = () => { submenu.classList.toggle('show') }

Solution

  • You can add a new class and toggle that class instead of manually showing and hiding div using style property.

    Also your outside click was not working because it was inside submenu click handler event.

    Please check below working code.

    let submenu = document.querySelector('.sub-menu')
    let submenuHead = document.querySelector('.submenuheader')
    
    openSubmenu = () => {
      submenu.classList.toggle('hidden');
    };
    
    submenuHead.addEventListener('click', openSubmenu);
    
    window.addEventListener('click', (Event) => {
      if (!submenuHead.contains(Event.target)) {
        submenu.classList.add('hidden');
      }
    });
    @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@200;300;400;500;600;700&display=swap');
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
      font-family: 'Poppins', 'Sans-serif';
    }
    
    body {
      min-height: 100vh;
    }
    
    nav {
      position: fixed;
      top: 0;
      left: 0;
      width: 100%;
      height: 70px;
      background: #333;
      box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
      z-index: 99;
    }
    
    nav .navbar {
      height: 100%;
      max-width: 1250px;
      width: 100%;
      display: flex;
      align-items: center;
      justify-content: space-between;
      margin: auto;
      padding: 0 50px;
    }
    
    .navbar .logo a {
      font-size: 20px;
      text-decoration: none;
      font-weight: 600;
      color: #ffffff;
    }
    
    nav .navbar .nav-links {
      line-height: 70px;
      height: 100%;
    }
    
    nav .navbar .links {
      display: flex;
    }
    
    nav .navbar .links li {
      position: relative;
      display: flex;
      align-items: center;
      justify-content: space-between;
      list-style: none;
      padding: 0 14px;
    }
    
    nav .navbar .links li:hover {
      background-color: #777;
    }
    
    nav .navbar .links li a {
      color: #ffffff;
      height: 100%;
      text-decoration: none;
      white-space: nowrap;
      font-size: 15px;
      font-weight: 500;
    }
    
    .navbar .links .submenuheader .sub-menu {
      position: absolute;
      top: 70px;
      left: 0;
      line-height: 40px;
      box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
      border-radius: 0 0 4px 4px;
      z-index: 2;
      background: #333;
    }
    
    .hidden {
      display: none;
    }
    <body>
      <nav>
        <div class="navbar">
          <div class="logo"><a href="#">Webpage</a></div>
          <ul class="links">
            <li>
              <a href="#">Home</a>
            </li>
            <li class="submenuheader">
              <a href="#">submenuheader</a>
              <ul class="sub-menu hidden">
                <li><a href="#">Item 1</a></li>
                <li><a href="#">Item 2</a></li>
                <li><a href="#">Item 3</a></li>
              </ul>
            </li>
          </ul>
        </div>
      </nav>
    </body>