Home > Software design >  Sub menu accordion closes when it should open (nested accordion logic seems off)
Sub menu accordion closes when it should open (nested accordion logic seems off)

Time:04-02

I have a multi-nested accordion menu is currently behaving glitchy.

When I'm clicking into a submenu (i.e. "what we deliver 2", it closes the main accordion and then when I open the main accordion, that's when the sub accordion opens. See this gif for a demo of my issue:

enter image description here

I'm trying to simply open and close each accordion on it's li click, but unsure why it closes the entire parent accordion and then appears once the parent accordion opens (it's the same behaviour when closing the sub accordions, as shown in the gif).

Demo:

$(function() {

  /*
  * define vars
  */

  const header = $(".header");
  const hamburger_trigger = $(".hamburger__trigger");
  const hamburger_popup = $(".hamburger__popup");

  /*
  * open hamburger on click
  */

  $(hamburger_trigger).click(function(e) {
    e.preventDefault();
    $(header).toggleClass("hamburger--open");
    $(hamburger_popup).toggleClass("active");
  });


  /*
  * hamburger submenu
  */

  $(".hamburger--has-submenu").click(function() {

    console.log("click");

    var child_menu = $(this).children(".hamburger__submenu");

    if ($(this).hasClass("hamburger__submenu--open")) {
      $(this).removeClass("hamburger__submenu--open");
      child_menu.removeClass("d-block");
    } else {
      $(this).addClass("hamburger__submenu--open");
      child_menu.addClass("d-block");

    }

  });


  // for children submenus

  $(".hamburger-trigger-submenu").click(function() {
    console.log("click");

    var child_menu = $(this).children(".hamburger__submenu");

    if ($(this).hasClass("hamburger__submenu--open")) {
      child_menu.removeClass("hamburger__submenu--open");
    } else {
      child_menu.addClass("hamburger__submenu--open");
    }

  });



});
/* HEADER */
.header {
  padding: 30px 0;
}

/* HAMBURGER */
.hamburger__trigger {
  cursor: pointer;
}
.hamburger__trigger:hover {
  color: green;
}
.hamburger__popup {
  background: black;
  visibility: hidden;
  display: none;
  height: 0;
  padding: 40px 15px 140px 15px;
  overflow-y: scroll;
}
.hamburger__popup.active {
  visibility: visible;
  -webkit-animation: fadeIn 0.3s;
  animation: fadeIn 0.3s;
  display: block;
  position: absolute;
  left: 0;
  top: 100px;
  width: 100%;
  height: 100vh;
  z-index: 9999;
}
.hamburger__popup-inner {
  display: flex;
  align-items: flex-start;
  flex-direction: column;
  overflow: auto;
  flex-grow: 1;
}
.hamburger__li > a {
  margin: 10px 0;
  display: block;
  text-decoration: none !important;
}
.hamburger__submenu--level-2, .hamburger__submenu--level-3, .hamburger__submenu--level-4 {
  display: none;
  padding-left: 10px;
}

/* GENERAL */
ul {
  list-style-type: none;
  margin: 0;
  padding: 0;
}

.background--black {
  background: #000000;
}

.color--white {
  color: #ffffff;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js" integrity="sha512-894YE6QWD5I59HgZOGReFYm4dnWc1Qt5NtvYSaNcOP u1T9qYdvdihz0PPSiiqn/ /3e7Jo4EaG7TubfWGUrMQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">

<header >

  <div >
    <div >
      <div >
        <div >
          <span >Click me</span>
        </div>
      </div>
    </div>
  </div>

  <div >
    <div >
      <nav >
        <ul >

          <!-- MAIN GROUP -->
          <li >
            <a  href="#">
              What we deliver
            </a>

            <!-- SUB MENU IN MAIN GROUP -->
            <ul >

              <li >
                <a  href="#">
                  <span>What we deliver 2</span>
                </a>
                <!-- SUB MENU WITHIN SUBMENU -->
                <ul >
                  <li >
                    <a  href="#">
                      What we deliver 2.1
                    </a>
                  </li>
                </ul>
                <!-- SUB MENU WITHIN SUBMENU END-->
              </li>

              <li >
                <a  href="#">
                  <span>What we deliver 3</span>
                </a>
                <!-- SUB MENU WITHIN SUBMENU -->
                <ul >
                  <li >
                    <a  href="#">
                      What we deliver 3.1
                    </a>
                  </li>
                </ul>
                <!-- SUB MENU WITHIN SUBMENU END-->
              </li>


            </ul>
            <!-- SUB MENU IN MAIN GROUP END -->


          </li>
          <!-- MAIN GROUP END -->


        </ul>

      </nav>
    </div>
  </div>

</header>

CodePudding user response:

You need to add e.stopPropagation(); (docs) within the $(".hamburger-trigger-submenu").click(...) handler to prevent the event from bubbling up to $(".hamburger--has-submenu").click(...).

Full Code:

$(function() {

  /*
  * define vars
  */

  const header = $(".header");
  const hamburger_trigger = $(".hamburger__trigger");
  const hamburger_popup = $(".hamburger__popup");

  /*
  * open hamburger on click
  */

  $(hamburger_trigger).click(function(e) {
    e.preventDefault();
    $(header).toggleClass("hamburger--open");
    $(hamburger_popup).toggleClass("active");
  });


  /*
  * hamburger submenu
  */

  $(".hamburger--has-submenu").click(function() {

    console.log("click");

    var child_menu = $(this).children(".hamburger__submenu");

    if ($(this).hasClass("hamburger__submenu--open")) {
      $(this).removeClass("hamburger__submenu--open");
      child_menu.removeClass("d-block");
    } else {
      $(this).addClass("hamburger__submenu--open");
      child_menu.addClass("d-block");

    }

  });


  // for children submenus

  $(".hamburger-trigger-submenu").click(function(e) {
    console.log("click");
    
    e.stopPropagation();
    
    var child_menu = $(this).children(".hamburger__submenu");

    if ($(this).hasClass("hamburger__submenu--open")) {
      child_menu.removeClass("hamburger__submenu--open");
    } else {
      child_menu.addClass("hamburger__submenu--open");
    }

  });



});
/* HEADER */
.header {
  padding: 30px 0;
}

/* HAMBURGER */
.hamburger__trigger {
  cursor: pointer;
}
.hamburger__trigger:hover {
  color: green;
}
.hamburger__popup {
  background: black;
  visibility: hidden;
  display: none;
  height: 0;
  padding: 40px 15px 140px 15px;
  overflow-y: scroll;
}
.hamburger__popup.active {
  visibility: visible;
  -webkit-animation: fadeIn 0.3s;
  animation: fadeIn 0.3s;
  display: block;
  position: absolute;
  left: 0;
  top: 100px;
  width: 100%;
  height: 100vh;
  z-index: 9999;
}
.hamburger__popup-inner {
  display: flex;
  align-items: flex-start;
  flex-direction: column;
  overflow: auto;
  flex-grow: 1;
}
.hamburger__li > a {
  margin: 10px 0;
  display: block;
  text-decoration: none !important;
}
.hamburger__submenu--level-2, .hamburger__submenu--level-3, .hamburger__submenu--level-4 {
  display: none;
  padding-left: 10px;
}

/* GENERAL */
ul {
  list-style-type: none;
  margin: 0;
  padding: 0;
}

.background--black {
  background: #000000;
}

.color--white {
  color: #ffffff;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js" integrity="sha512-894YE6QWD5I59HgZOGReFYm4dnWc1Qt5NtvYSaNcOP u1T9qYdvdihz0PPSiiqn/ /3e7Jo4EaG7TubfWGUrMQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">

<header >

  <div >
    <div >
      <div >
        <div >
          <span >Click me</span>
        </div>
      </div>
    </div>
  </div>

  <div >
    <div >
      <nav >
        <ul >

          <!-- MAIN GROUP -->
          <li >
            <a  href="#">
              What we deliver
            </a>

            <!-- SUB MENU IN MAIN GROUP -->
            <ul >

              <li >
                <a  href="#">
                  <span>What we deliver 2</span>
                </a>
                <!-- SUB MENU WITHIN SUBMENU -->
                <ul >
                  <li >
                    <a  href="#">
                      What we deliver 2.1
                    </a>
                  </li>
                </ul>
                <!-- SUB MENU WITHIN SUBMENU END-->
              </li>

              <li >
                <a  href="#">
                  <span>What we deliver 3</span>
                </a>
                <!-- SUB MENU WITHIN SUBMENU -->
                <ul >
                  <li >
                    <a  href="#">
                      What we deliver 3.1
                    </a>
                  </li>
                </ul>
                <!-- SUB MENU WITHIN SUBMENU END-->
              </li>


            </ul>
            <!-- SUB MENU IN MAIN GROUP END -->


          </li>
          <!-- MAIN GROUP END -->


        </ul>

      </nav>
    </div>
  </div>

</header>

CodePudding user response:

you can solve it with simple pseudo class in css named :focus-within;

:focus-within CSS pseudo-class matches an element if the element or any of its descendants are focused.

    ul:focus-within {
      display: block;
    }

(no need complex js )

  • Related