Why the sub-menus disappear in a hover-over accordion

Viewed 226

I am trying to make a hover-over accordion.

What I would like to achieve:

When the mouse hovers over a menu, all sub-menus underneath open, but the remaining menus remain collapsed. (Simply, it's an accordion, but it's triggered by hovering instead of clicking.)

What I have achieved:

When I hover the parent menu, it opens the sub-menus.

What I haven't achieved:

Once my mouse leaves the parent menu, even if it is still over the sub-menu, the sub-menu collapses. (Simply, my mouse cannot leave the parent menu. I cannot click the sub-menu links.)

HTML:

 <div class="accordion">
          <ul>
            <li class="parentmenu"><a href="#"><i class="fas fa-home"></i> Home</a></li>
            <ul class="dropdown">
              <li><a href="#">Home Submenu 1</a></li>
              <li><a href="#">Home Submenu 2</a></li>
            </ul>
            <li class="parentmenu"><a href="#"><i class="fas fa-address-card"></i> About</a></li>
            <ul class="dropdown">
              <li><a href="#">About Submenu 1</a></li>
              <li><a href="#">About Submenu 2</a></li>
            </ul>
            <li class="parentmenu"><a href="#"><i class="far fa-edit"></i> Services</a></li>
            <ul class="dropdown">
              <li><a href="#">Services Submenu 1</a></li>
              <li><a href="#">Services Submenu 2</a></li>
            </ul>
            <li class="parentmenu"><a href="#"><i class="fas fa-id-card-alt"></i> Contact</a></li>
            <ul class="dropdown">
              <li><a href="#">Contact Submenu 1</a></li>
              <li><a href="#">Contact Submenu 2</a></li>
            </ul>
          </ul>
        </div>

CSS:

.dropdown{
  display:none;
}

.deployed {
  display: block;
}

JQuery:

<script>
      jQuery(document).ready(function() {
        $('.parentmenu').hover(function() {
        if ($(this).next().css('display') == 'none'){
            $(this).next().addClass('deployed');
        }
          else {
          $(this).next().removeClass('deployed');
        }
        });
      });
2 Answers

As soon as your mouse leaves the li.parentmenu, the hover effect you applied with jquery is not working anymore, since your mouse no longer is above this element.

It is also semantically not correct to have an <ul> inside an <ul>. You must wrap the nested <ul> inside an <li>element.

More infos to the ul element and its allowed content here: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul

Applying the right semantic nicely brings us to one solution you could apply.


Possible solution

In your HTML you could wrap you ul.dropdown inside the li.parentmenu.

Following this you can't use the .next() selector anymore for your if statement and the class action. Instead you could use .find('.dropdown') for example.

Now when you hover your ul.dropdown you are also still hovering the li.parentmenu and your dropdown stays visible.


Here you can find a working JSFiddle example: https://jsfiddle.net/7hwug3jz/


And here is your HTML and jQuery code with the changes I just explained.

HTML

<div class="accordion">
  <ul>
    <li class="parentmenu">
      <a href="#"><i class="fas fa-home"></i> Home</a>
      <ul class="dropdown">
        <li><a href="#">Home Submenu 1</a></li>
        <li><a href="#">Home Submenu 2</a></li>
      </ul>
    </li>

    <li class="parentmenu">
      <a href="#"><i class="fas fa-address-card"></i> About</a>
      <ul class="dropdown">
        <li><a href="#">About Submenu 1</a></li>
        <li><a href="#">About Submenu 2</a></li>
      </ul>
    </li>

    <li class="parentmenu">
      <a href="#"><i class="far fa-edit"></i> Services</a>
      <ul class="dropdown">
        <li><a href="#">Services Submenu 1</a></li>
        <li><a href="#">Services Submenu 2</a></li>
      </ul>
    </li>

    <li class="parentmenu">
      <a href="#"><i class="fas fa-id-card-alt"></i> Contact</a>
      <ul class="dropdown">
        <li><a href="#">Contact Submenu 1</a></li>
        <li><a href="#">Contact Submenu 2</a></li>
      </ul>
    </li>

  </ul>
</div>

jQuery

jQuery(document).ready(function() {
  $('.parentmenu').hover(function() {
    if ($(this).find('.dropdown').css('display') == 'none'){
      $(this).find('.dropdown').addClass('deployed');
    }
    else {
      $(this).find('.dropdown').removeClass('deployed');
    }
  });
});

Here is the simpler and clean way to do it, if doing it in CSS is not an issue here.

a {
  text-decoration: none;
}

nav {
  font-family: monospace;
}

ul {
  background: darkorange;
  list-style: none;
  margin: 0;
  padding-left: 0;
}

li {
  color: #fff;
  background: gray;
  display: block;
  float: left;
  padding: 1rem;
  position: relative;
  text-decoration: none;
  transition-duration: 0.5s;
}

li a {
  color: #fff;
}

li:hover {
  background: red;
  cursor: pointer;
}

ul li ul {
  background: orange;
  visibility: hidden;
  opacity: 0;
  min-width: 5rem;
  position: absolute;
  transition: all 0.5s ease;
  margin-top: 1rem;
  left: 0;
  display: none;
}

ul li:hover>ul,
ul li ul:hover {
  visibility: visible;
  opacity: 1;
  display: block;
}

ul li ul li {
  clear: both;
  width: 100%;
}
<nav role="navigation">
  <ul>
    <li><a href="#">Menu-1</a></li>
    <li><a href="#">Menu-2</a>
      <ul class="dropdown">
        <li><a href="#">Sub-1</a></li>
        <li><a href="#">Sub-2</a></li>
        <li><a href="#">Sub-3</a></li>
      </ul>
    </li>
    <li><a href="#">Menu-3</a></li>
  </ul>
</nav>

Related