Dropdown menu on click

I am trying to convert my dropdown menu on hover to work on click with a bit of JS, but I’m getting nothing when I click. No errors, no suggestion as to where I’m failing.

(function() {
  Array.prototype.forEach.call(document.getElementsByClassName("submenu"), function(el) {
    el.style.marginTop = "-99px";
    el.addEventListener("click", function() {
      if (el.style.marginTop === "0") {
        el.style.marginTop = "-99px";
      } else {
        el.style.marginTop = "0";
      }
    });
  })
})();

CSS:

.navWrap {
  margin: .75rem auto 0;
  padding: 0 var(--gutter);
}
nav {
  vertical-align: top;
  text-align: left;
  text-transform: uppercase;
  border-top: 1px solid var(--colour1);
  border-bottom: 1px solid var(--colour1);
}
nav ul {
  list-style: none;
  margin: 0;
  padding: 0;
}
nav li {
  display: inline-block;
  padding: 0 .15em;
}
nav ul ul {
  z-index: 1;
  position: absolute;
  top: auto;
  left: -2em;
  right: -2em;
  text-align: center;
  margin-top: -99em;
  padding: 0 .25em;
} /*
nav ul li:hover ul {
  margin-top: 0;
} */
nav ul ul li {
  display: block;
  width: auto;
}
nav a {
  display: block;
  text-decoration: none;
  background-color: #fff;
  color: #507399;
  padding: .4em 0;
  transition: color .3s ease-in-out;
  box-shadow: none;
}

Shortened menu:

<div class="navWrap">
  <nav>
    <ul>
      <li><a href="church.php">St Andrew’s</a></li>
      <li><a href="#">Social</a>
        <ul class="submenu">
          <li><a href="village-hall.php">Village Hall</a></li>
          <li><a href="events.php">Events</a></li>
        </ul>
      </li>
    </ul>
  </nav>
</div>

The problem is that the anchor tag is receiving the click and the event handler isn’t firing.

You can achieve what you want like this:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Dropdown</title>
    <style>
      .navWrap {
        margin: .75rem auto 0;
        padding: 0 var(--gutter);
      }
      nav {
        vertical-align: top;
        text-align: left;
        text-transform: uppercase;
        border-top: 1px solid var(--colour1);
        border-bottom: 1px solid var(--colour1);
      }
      nav ul {
        list-style: none;
        margin: 0;
        padding: 0;
      }
      nav li {
        display: inline-block;
        padding: 0 .15em;
      }
      nav ul ul {
        z-index: 1;
        position: absolute;
        top: auto;
        left: -2em;
        right: -2em;
        text-align: center;
        margin-top: -99em;
        padding: 0 .25em;
      } 
      nav ul ul li {
        display: block;
        width: auto;
      }
      nav a, .submenu > span {
        display: block;
        text-decoration: none;
        background-color: #fff;
        color: #507399;
        padding: .4em 0;
        transition: color .3s ease-in-out;
        box-shadow: none;
      }

      .submenu ul {
        margin-top: -99px;
      }

      .submenu > span:hover {
        cursor: pointer;
      }
    </style>

  </head>
  <body>
    <div class="navWrap">
      <nav>
        <ul>
          <li><a href="church.php">St Andrew’s</a></li>
          <li class="submenu">
            <span>Social</span>
            <ul>
              <li><a href="village-hall.php">Village Hall</a></li>
              <li><a href="events.php">Events</a></li>
            </ul>
          </li>
        </ul>
      </nav>
    </div>

    <script>
      const submenus = document.querySelectorAll('.submenu');

      [...submenus].forEach((subMenu) => {
        const dropDown = subMenu.querySelector('ul');

        subMenu.addEventListener('click', () => {
          if (dropDown.style.marginTop === '0px') {
            dropDown.style.marginTop = '-99px';
          } else {
            dropDown.style.marginTop = '0px';
          }
        });
      });
    </script>
  </body>
</html>

Maybe you could also keep the CSS to make it hover, then remove it in your JS so that teh menu works if JS is disabled.

HTH

2 Likes

Hi there gandalf458,

have you considered using a possible CSS
only solution, like this example perhaps…

<!DOCTYPE HTML>
<html lang="en">
<head>

<meta charset="utf-8">
<meta name="viewport" content="width=device-width,height=device-height,initial-scale=1">

<title>Untitled Document</title>

<!--<link rel="stylesheet" href="screen.css" media="screen">-->

<style media="screen">
ul {
    margin: 0;
    padding: 0;
    list-style: none;
 }
 
li {
    display: inline-block;
    padding: 0 0.15em;
 }
 
ul ul {
    position: absolute;
    z-index: 1;
    top: auto;
    left: -2em;
    right: -2em;
    margin-top: -99em;
    padding: 0 0.25em;
    text-align: center;
 }
 
 ul ul li {
    display: block;
    width: auto;
 }
 
 a, label {
    display: block;
    padding: 0.4em 0;
    background-color: #fff;
    color: #507399;
    text-decoration: none;
    transition: color 0.5s ease-in-out;
    box-shadow: none;
    cursor: pointer;
 }
 
#cb1:checked ~ ul .submenu1,
#cb2:checked ~ ul .submenu2 {
    margin-top: 0;
 }

#cb1:checked ~ ul label[for=cb1],
#cb2:checked ~ ul label[for=cb2] {
    color: #f00;
 } 
</style>

</head>
<body> 

 <input id="cb1" type="radio" name="r" hidden>
 <input id="cb2" type="radio" name="r" hidden>
 <input id="cb3" type="radio" name="r" hidden>

 <ul>
  <li><a href="church.php">St Andrew’s</a></li>
  <li><a href="#"><label for="cb1">Social</label></a>
   <ul class="submenu1">
    <li><a href="village-hall.php">Village Hall</a></li>
    <li><a href="events.php">Events</a></li>
   </ul>
  </li>
  <li><a href="#"><label for="cb2">Other Stuff</label></a>
   <ul class="submenu2">
    <li><a href="#">Link 1</a></li>
    <li><a href="#">Link 2</a></li>
   </ul>
  </li>
  <li><a href="#"><label for="cb3">Close Dropdown</label></a>
 </ul>
 
</body>
</html>

coothead

3 Likes

Many thanks guys. Two options, I am a lucky wizard! :slight_smile:

2 Likes