0

I'm trying to build a sidebar collapsible menu. The goal is to display #sidenav whenever the user clicks on the hamburger menu, and close the #sidenav if the user clicks outside of the menu while the menu is open.

Right now I'm running into an issue where the part of the script that closes the sidenav menu, window.onclick, is being fired whenever the user clicks on the hamburger icon which essentially closing the menu before it can ever open. What am I doing wrong? What is keeping the menu from functioning as I am intending?

  var mininav = true;
  var sidenav = document.getElementById("sidenav");

  function toggleSidenav() {
    if (mininav) {
      sidenav.style.width = "300px";
      this.mininav = false;
    } else {
      sidenav.style.width = "0px";
      this.mininav = true;
    }
  }
  window.onclick = function(event) {                      
    if (mininav == false) {
      if (event.target != sidenav) {sidenav.style.width = "0px";}
    }
  }
  nav {
    z-index: 10;
    display: flex;
    align-items: center;
    position: fixed;
    top: 0; left: 0;
    width: 100vw; height: 65px;
    font-size: x-large;
    font-family: 'Noto Sans JP', sans-serif;
    background-color: white;
    border-bottom: 1px solid lightgray}

  /* -------- [MAIN NAV] -------- */
  .mainnav ul {
    margin: 0;
    margin-left: 250px;
    padding: 0;
    overflow: hidden;
    list-style-type: none}
    .mainnav li {float: left}
    .mainnav li:hover {background-color: #F6F6F6; border-bottom: 1px solid purple}

  .mainnav li a {
    display: block;
    text-decoration: none;
    text-align: center;
    color: #5F6368;
    font-size: 20px;
    padding: 21px 20px;}

  /* -------- [SIDE NAV] -------- */
  .sidenav .container {
    z-index: 11;
    position: absolute;
    top: 0; left: 0;
    width: 0px; height: 100vh;
    transition: 0.5s;
    background-color: white;
    border-right: 1px solid lightgray;
    box-shadow: 10px 0px 4px -10px rgba(0,0,0,0.51);}

  .sidenav .top, .sidenav .classes {
    width: 100%;
    padding: 8px 0px;}

  .sidenav .top {border-bottom: 1px solid lightgray}

  .container ul {
    margin: 0;
    padding: 0;
    overflow: hidden;
    list-style-type: none}
    .container li {width: 95%}

  .container li a {
    display: block;
    text-decoration: none;
    color: #5F6368;
    font-size: 20px;
    padding: 21px 20px;
    margin-bottom: 10px;
    border-top-right-radius: 40px;
    border-bottom-right-radius: 40px;}
    .container li a:hover {background-color: #F2F2F2}
    .container li a.active {background-color: #EEEEEE}

  /* -------- [MISC SETTINGS] -------- */
  .profilepic {margin-right: 15px}
  .small-pic img{width: 20px;}
  .medium-pic img{width: 40px;}

  .hamburger {margin-left: 15px}
  .hamburger .line {
    width: 22px;
    height: 2px;
    background-color: darkgray;
    margin: 6px 0;}

  .is-left {float: left;}
  .is-right {margin-left: auto; order: 2;}
  .is-circle {clip-path: circle();}
<nav>
  <div class='sidenav'>
    <div class='hamburger is-left' onclick='toggleSidenav()'>
      <div class='line'></div>
      <div class='line'></div>
      <div class='line'></div>
    </div>
    <div id='sidenav' class='container'>
      <div class='top'>
        <ul>
          <li><a href=''>Main Menu</a></li>
        </ul>
      </div>
      <div class='classes'>
        <ul>
          <li><a class='active' href=''>Class One</a></li>
          <li><a href=''>Class Two</a></li>
          <li><a href=''>Class Three</a></li>
        </ul>
      </div>
    </div>
  </div>
  <div class='mainnav'>
    <ul>
      <li><a href=''>Dash</a></li>
      <li><a href=''>Grades</a></li>
      <li><a href=''>Tasks</a></li>
      <li><a href=''>Skills</a></li>
    </ul>
  </div>
  <div class='profilepic medium-pic is-circle is-right'>
    <img src='https://classcolonies.com/resources/pics/students/68.jpg'>
  </div>
</nav>
Johnathan
  • 47
  • 5

2 Answers2

0

Your code is correct but it was not working because of Event Bubbling. When you click on child element, the event gets propagated. You can learn more about it What is event bubbling and capturing?.

I added code event.stopPropagation();, now it is working.

var mininav = true;
  var sidenav = document.getElementById("sidenav");

  function toggleSidenav(event) {
    if (mininav) {
      sidenav.style.width = "300px";
      this.mininav = false;
    } else {
      sidenav.style.width = "0px";
      this.mininav = true;
    }
    event.stopPropagation();
    
  }
  window.onclick = function(event) {   
    if (mininav == false) {
      if (event.target != sidenav) {sidenav.style.width = "0px";}
    }
  }
nav {
    z-index: 10;
    display: flex;
    align-items: center;
    position: fixed;
    top: 0; left: 0;
    width: 100vw; height: 65px;
    font-size: x-large;
    font-family: 'Noto Sans JP', sans-serif;
    background-color: white;
    border-bottom: 1px solid lightgray}

  /* -------- [MAIN NAV] -------- */
  .mainnav ul {
    margin: 0;
    margin-left: 250px;
    padding: 0;
    overflow: hidden;
    list-style-type: none}
    .mainnav li {float: left}
    .mainnav li:hover {background-color: #F6F6F6; border-bottom: 1px solid purple}

  .mainnav li a {
    display: block;
    text-decoration: none;
    text-align: center;
    color: #5F6368;
    font-size: 20px;
    padding: 21px 20px;}

  /* -------- [SIDE NAV] -------- */
  .sidenav .container {
    z-index: 11;
    position: absolute;
    top: 0; left: 0;
    width: 0px; height: 100vh;
    transition: 0.5s;
    background-color: white;
    border-right: 1px solid lightgray;
    box-shadow: 10px 0px 4px -10px rgba(0,0,0,0.51);}

  .sidenav .top, .sidenav .classes {
    width: 100%;
    padding: 8px 0px;}

  .sidenav .top {border-bottom: 1px solid lightgray}

  .container ul {
    margin: 0;
    padding: 0;
    overflow: hidden;
    list-style-type: none}
    .container li {width: 95%}

  .container li a {
    display: block;
    text-decoration: none;
    color: #5F6368;
    font-size: 20px;
    padding: 21px 20px;
    margin-bottom: 10px;
    border-top-right-radius: 40px;
    border-bottom-right-radius: 40px;}
    .container li a:hover {background-color: #F2F2F2}
    .container li a.active {background-color: #EEEEEE}

  /* -------- [MISC SETTINGS] -------- */
  .profilepic {margin-right: 15px}
  .small-pic img{width: 20px;}
  .medium-pic img{width: 40px;}

  .hamburger {margin-left: 15px}
  .hamburger .line {
    width: 22px;
    height: 2px;
    background-color: darkgray;
    margin: 6px 0;}

  .is-left {float: left;}
  .is-right {margin-left: auto; order: 2;}
  .is-circle {clip-path: circle();}
<nav>
  <div class='sidenav'>
    <div class='hamburger is-left' onclick='toggleSidenav(event)'>
      <div class='line'></div>
      <div class='line'></div>
      <div class='line'></div>
    </div>
    <div id='sidenav' class='container'>
      <div class='top'>
        <ul>
          <li><a href=''>Main Menu</a></li>
        </ul>
      </div>
      <div class='classes'>
        <ul>
          <li><a class='active' href=''>Class One</a></li>
          <li><a href=''>Class Two</a></li>
          <li><a href=''>Class Three</a></li>
        </ul>
      </div>
    </div>
  </div>
  <div class='mainnav'>
    <ul>
      <li><a href=''>Dash</a></li>
      <li><a href=''>Grades</a></li>
      <li><a href=''>Tasks</a></li>
      <li><a href=''>Skills</a></li>
    </ul>
  </div>
  <div class='profilepic medium-pic is-circle is-right'>
    <img src='https://classcolonies.com/resources/pics/students/68.jpg'>
  </div>
</nav>
Md Junaid Alam
  • 1,131
  • 13
  • 20
  • Although this answer is correct, it stops the sidenav from opening when you click on the middle of hamburger lines sometimes. So it doesn't actually fix the issue, but causes side effects. No offense to @MdJunaidAlam, it's a good thought from him. – Salvino D'sa Aug 03 '21 at 05:11
0

This works for me:

var isToggled = false;
var sidenav = document.getElementById("sidenav");

function toggleSidenav() {
  if (!isToggled) {
    sidenav.style.width = "300px";
  } else {
    sidenav.style.width = "0px";
  }
  isToggled = !isToggled;
}

window.onclick = function(event) {
  if (isToggled && !event.target.classList.contains('hamburger') && !event.target.classList.contains('line')) {
    toggleSidenav();
  }
}
nav {
  z-index: 10;
  display: flex;
  align-items: center;
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 65px;
  font-size: x-large;
  font-family: 'Noto Sans JP', sans-serif;
  background-color: white;
  border-bottom: 1px solid lightgray
}

/* -------- [MAIN NAV] -------- */
.mainnav ul {
  margin: 0;
  margin-left: 250px;
  padding: 0;
  overflow: hidden;
  list-style-type: none
}

.mainnav li {
  float: left
}

.mainnav li:hover {
  background-color: #F6F6F6;
  border-bottom: 1px solid purple
}

.mainnav li a {
  display: block;
  text-decoration: none;
  text-align: center;
  color: #5F6368;
  font-size: 20px;
  padding: 21px 20px;
}

/* -------- [SIDE NAV] -------- */
.sidenav .container {
  z-index: 11;
  position: absolute;
  top: 0;
  left: 0;
  width: 0px;
  height: 100vh;
  transition: 0.5s;
  background-color: white;
  border-right: 1px solid lightgray;
  box-shadow: 10px 0px 4px -10px rgba(0, 0, 0, 0.51);
}

.sidenav .top,
.sidenav .classes {
  width: 100%;
  padding: 8px 0px;
}

.sidenav .top {
  border-bottom: 1px solid lightgray
}

.container ul {
  margin: 0;
  padding: 0;
  overflow: hidden;
  list-style-type: none
}

.container li {
  width: 95%
}

.container li a {
  display: block;
  text-decoration: none;
  color: #5F6368;
  font-size: 20px;
  padding: 21px 20px;
  margin-bottom: 10px;
  border-top-right-radius: 40px;
  border-bottom-right-radius: 40px;
}

.container li a:hover {
  background-color: #F2F2F2
}

.container li a.active {
  background-color: #EEEEEE
}

/* -------- [MISC SETTINGS] -------- */
.profilepic {
  margin-right: 15px
}

.small-pic img {
  width: 20px;
}

.medium-pic img {
  width: 40px;
}

.hamburger {
  margin-left: 15px
}

.hamburger .line {
  width: 22px;
  height: 2px;
  background-color: darkgray;
  margin: 6px 0;
}

.is-left {
  float: left;
}

.is-right {
  margin-left: auto;
  order: 2;
}

.is-circle {
  clip-path: circle();
}
<nav>
  <div class='sidenav'>
    <div class='hamburger is-left' onclick='toggleSidenav()'>
      <div class='line'></div>
      <div class='line'></div>
      <div class='line'></div>
    </div>
    <div id='sidenav' class='container'>
      <div class='top'>
        <ul>
          <li><a href=''>Main Menu</a></li>
        </ul>
      </div>
      <div class='classes'>
        <ul>
          <li><a class='active' href=''>Class One</a></li>
          <li><a href=''>Class Two</a></li>
          <li><a href=''>Class Three</a></li>
        </ul>
      </div>
    </div>
  </div>
  <div class='mainnav'>
    <ul>
      <li><a href=''>Dash</a></li>
      <li><a href=''>Grades</a></li>
      <li><a href=''>Tasks</a></li>
      <li><a href=''>Skills</a></li>
    </ul>
  </div>
  <div class='profilepic medium-pic is-circle is-right'>
    <img src='https://classcolonies.com/resources/pics/students/68.jpg'>
  </div>
</nav>
Salvino D'sa
  • 4,018
  • 1
  • 7
  • 19