A simple vanilla JS menu toggle

The following code is of a burger menu and its toggler button I tried to create in vanilla JS (I don’t want to use jQuery at all).

CSS:

#menu-mainmenu, #menu-mainmenu ul {display: block; padding: 0 1em 0 1em}
#menu-mainmenu li {display: block; margin: 1em auto 0; list-style-type: none}
#menu-mainmenu a {display: block; text-align: center; font-family: tahoma; color: #000}
#menu-mainmenu a:hover, .current-menu-item {color: #d3b258}

Vanilla JavaScript:

let menu = document.querySelector('#menu-mainmenu');
let menuToggle = document.querySelector('.menuToggle');

if (window.innerWidth <= 768) {
    menu.style.display = "none";

    menuToggle.addEventListener("click", ()=>{
        menu.style.display = "block";
    });        
}

As for now I’m just stuck on display: block.

How could I add toggling ability to toggle between display: block and display: none when clicking the burger toggler?

Edit: This is an online test site that I don’t want to be indexed at all (I mistakenly tested online) so I avoid sharing a link to it.

You got some HTML to go with that?

Don’t do the hiding and showing of the menu and toggle button via js but use css media queries instead as that is what they were designed for.

All the js needs to do is toggle the menu on and off when the toggle button is clicked. If you hide the toggle button at larger screen sizes with media queries then it won’t get opened by accident. Also add css classes with js to open the menu rather than directly using the style attribute.

Your example would not work if someone resizes their window unless they also clicked refresh and then would not work when the window was opened wider again.

6 Likes

Here’s how you’d use JS to toggle the visibility of an element.

const menu = document.querySelector('.menu');
const menuToggle = document.querySelector('.menuToggle');

menuToggle.addEventListener('click', (e) => {
  e.preventDefault();

  if (window.getComputedStyle(menu).display === 'block') {
    menu.style.display = 'none';
  } else  {
    menu.style.display = 'block';
  }
});

As you can read here, you can use an element’s offsetParent property to check if it is hidden via the display style property.

Here’s a runnable example.

<!doctype html>
<html>

<head>
  <meta charset="utf-8">
  <title>Menu toggle</title>
  <style>
    .menu{
      display: none;
    }
  </style>
</head>

<body>

<a href="#" class="menuToggle">Toggle Menu</a>

<nav class="menu">
  <ul>
    <li><a href="#">Home</a></li>
    <li><a href="#">About</a></li>
    <li><a href="#">Contact</a></li>
  </ul>
</nav>

<script>
  const menu = document.querySelector('.menu');
  const menuToggle = document.querySelector('.menuToggle');

  menuToggle.addEventListener('click', (e) => {
    e.preventDefault();

    if (window.getComputedStyle(menu).display === 'block') {
      menu.style.display = 'none';
    } else  {
      menu.style.display = 'block';
    }
  });
</script>
</body>

</html>
3 Likes

How would you go about animating the show/hide action using CSS, Paul?

I’d like to learn more about this. Could you point me in the right direction?

Do not use JavaScript at all, is the answer to your query.

When it comes to things like adjusting the presentation based on the screen width, CSS media queries are the much better and more reliable technique to use instead.

@media screen and (max-width: 768px) {
  #menu-mainmenu {
    display: none;
  }
  #menu-mainmenu.toggle {
    display: block;
  }
}
@media screen and (min-width: 769px) {
  #menu-mainmenu {
    display: initial;
  }
  .menuToggle {
    display: none;
  }
}

I’m put together a quick working example with the word “main menu” instead of an actual menu at https://jsfiddle.net/qt1804mm/

Per comments by @PaulOB and @Paul_Wilkins I’ve relied more on CSS media queries and edited the CSS and JS in the question.

There is a minor problem though — if I resize to desktop and than go back to mobile I need to double click the toggler.

Is that something that can be experienced and troubleshooted on the jsfiddle example? If not, we’ll need to see some demo code from you that demonstrates the problem.

Sure, I did some mistakes here, first by relying on an online test environment I shouldn’t link to as I fear of SEO damage. Sorry. My bad. :frowning:

@James_Hibbard this code based on your example above seems to work fine besides one small issue — if you resize to desktop, then back to mobile, you need to double click the toggler:

CSS:

#menu-mainmenu {display: none}
#menu-mainmenu ul {display: block; padding: 0 1em 0 1em}
#menu-mainmenu li {display: block; margin: 1em auto 0; list-style-type: none}
#menu-mainmenu a {display: block; text-align: center; font-family: tahoma; color: #000}
#menu-mainmenu a:hover, .current-menu-item {color: #d3b258}

@media screen and (min-width: 769px) {
	#menu-mainmenu {display: block}
	#menu-mainmenu, #menu-mainmenu ul {text-align: center}
	#menu-mainmenu li {display: inline-block; padding: 1em 0 1em 2em}
	#menu-mainmenu a {display: inline-block; max-width: initial; padding: 1em 0 1em 2em; margin: -1em 0 -1em -2em}
}

Vanilla JavaScript:

const menu = document.querySelector('.menu');
const menuToggle = document.querySelector('.menuToggle');

menuToggle.addEventListener('click', (e)=>{
    e.preventDefault();
    if (window.getComputedStyle(menu).display === 'block') {
    menu.style.display = 'none';
    } else  {
    menu.style.display = 'block';
    }
});

Borrowing Paul’s js then I would hide the nav menu off to the side (no display none) and then when the class is added you can slide it into view with a transition. You can’t animate display:none/block.

This is very rough but I usually do something like this:

That’s the basics anyway.

Thank you very much :slight_smile:

I had a play around with the demo and have a couple more questions. I’ll see what I can find on Google, then start a new thread if I can’t find what I’m looking for.

Have a great NYE!

1 Like

Can you post some HTML to go with the CSS / JavaScript. It doesn’t have to be a link to your site (or even your real code), rather just a snippet that makes it possible to recreate what you are working with.

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.