Create Better Divi Headers

Expand and Collapse Divi Vertical Menu Submenus on Click

by | Aug 17, 2018 | 45 comments

In this tutorial we are going to make the Divi Vertical Menu submenus expand/collapse when the parent menu items are clicked.

We can create such a vertical menu in two different ways: (1) using the Divi MadMenu extension, and (2) using custom code with Divi theme Vertical Navigation, and in this tutorial I’m providing both solutions.

Solution #1: Using the Divi MadMenu Vertical Menu Module

This solution allows you to create the vertical navigation using the Divi MadMenu Vertical Menu module.

This is a much more flexible solution (compared to the Solution #2 below) allowing you to create the vertical navigation using the power of the Divi Builder.

So, if you don’t want to deal with any code then this solution is a great option for you, you can learn more here.

Otherwise, you can try the Solution #2 below, works with the Divi theme native Vertical Navigation.

Solution #2: Using Custom Code with Divi Theme Vertical Navigation

By default the submenus of the Divi theme Vertical Navigation show up when you hover over the parent menu item, and if there are multiple submenu levels then the lower level submenu appears to the left or to the right of the parent submenu (depending on the position of vertical menu: left or right).

We will change this behavior so that the submenus expand/collapse when clicking the parent menu item while being nested inside one another rather than on the left or right hand side.

To implement this collapsing submenus effect for the Divi theme Vertical Navigation we need to use custom JS and CSS.

We’ll use CSS to change the positioning and styling of submenus, and the JS part will make the submenus expand/collapse when clicking the parent menu item.

The JS code used in this tutorial is basically a modified version of the code provided by ET for collapsing the mobile menu submenus (you can read about it here, and you can check out our own version as well).

First let’s change the positioning and styling of the submenus. The important point here is that the submenu positioning needs to be changed from absolute to relative and the left offset set to 0(zero) to place the submenus underneath the parent menu items.

The submenus are animated using CSS by default but we need to disable the animation since we will use jQuery slideToggle() function to animate submenus when expanding/collapsing.

The initial state of submenus needs to be closed, so, we’ll hide them. Also the width of submenu needs to be changed to auto in order to fit into the header container.

/* adjust positioning and styling of submenu */
.et_vertical_nav #main-header #top-menu li ul {
  position: relative;
  display: none;
  top: 0;
  left: 0;
  width: auto;
  border-left-width: 0;
  opacity: 1;
  -webkit-animation: none;
          animation: none;
  visibility: visible;
  -webkit-box-shadow: none;
          box-shadow: none;
  background-color: rgba(0, 0, 0, 0.1);
  margin-bottom: 15px;
  -webkit-transition: none;
  -o-transition: none;
  transition: none;
}

Next let’s decrease header container left and right margin to provide more room to submenus.

/* decrease the menu container left and right margin */
.et_vertical_nav #main-header .container {
  margin: 0 20px;
}

If you have the Fixed header enabled and submenus with many menu items then expanding them all at once may make some of the menu items not accessible due to the fact that the menu does not fit into the screen.

To prevent this we need to make the fixed header container scrollable vertically when the menu items do not fit in.

/* make the fixed header scrollable */
.et_vertical_nav.et_vertical_fixed #page-container #main-header {
  overflow-y: auto;
}
Then decrease submenu top and bottom padding.
/* decrease submenu top and bottom padding */
.nav li ul {
  padding: 5px 0;
}
Adjust lower level submenu positioning and remove the box-shadow.
/* adjust the lower level submenu positioning and remove box-shadow */
.et_vertical_nav #main-header #top-menu li ul ul {
   	top: 0;
  left: 0;
  -webkit-box-shadow: none;
          box-shadow: none;
}
Adjust main menu item links spacing.
/* adjust the menu item links spacing */
.et_vertical_nav #main-header #top-menu > li > a {
  margin-right: 0px;
  padding-right: 0px;
}
Remove main menu parent item down arrow right offset.
/* adjust parent item down arrow position */
.et_vertical_nav #main-header #top-menu > li > a:after {
  right: 0px;
}
Decrease the lower level submenu parent item down arrow right offset.
/* adjust lower level parent item down arrow position */
.et_vertical_nav #top-menu li .menu-item-has-children>a:first-child:after {
  right: 10px;
}
Adjust the submenu item left and right padding.
/* decrease the submenu item left and right padding */
#top-menu li li {
  padding: 0 10px;
}
Change submenu item link width and padding.
/* adjust submenu item link width and padding */
#top-menu li li a {
   	width: auto;
   	padding: 6px;
}
Finally, remove the right border and right offset of the right vertical menu submenu.
/* remove right border and adjust positioning of the right vertical menu submenu */
.et_vertical_nav.et_vertical_right #main-header #top-menu li ul {
  right: 0;
  border-right-width: 0;
}

Bringing all of the CSS together

Now let’s bring all of the CSS snippets above together and wrap them in a media query with min-width of 981px to make sure this CSS applies to desktop menu only.
@media all and (min-width: 981px) {

  /* define positioning and styling for submenu */
  .et_vertical_nav #main-header #top-menu li ul {
    position: relative;
    display: none;
    top: 0;
    left: 0;
    width: auto;
    border-left-width: 0;
    opacity: 1;
    -webkit-animation: none;
        animation: none;
    visibility: visible;
    -webkit-box-shadow: none;
        box-shadow: none;
    background-color: rgba(0, 0, 0, 0.1);
    margin-bottom: 15px;
    -webkit-transition: none;
    -o-transition: none;
    transition: none;
  }
  
  /* decrease the menu container left and right padding */
  .et_vertical_nav #main-header .container {
    margin: 0 20px;
  }

  /* make the fixed header scrollable */
  .et_vertical_nav.et_vertical_fixed #page-container #main-header {
    overflow-y: auto;
  }

  /* decrease the submenu top and bottom padding */
  .nav li ul {
    padding: 5px 0;
  }
  
  /* adjust the lower level submenu positioning and remove box-shadow */
  .et_vertical_nav #main-header #top-menu li ul ul {
    top: 0;
    left: 0;
    -webkit-box-shadow: none;
            box-shadow: none;
  }
  
  /* adjust the menu item links spacing */
  .et_vertical_nav #main-header #top-menu > li > a {
    margin-right: 0px;
    padding-right: 0px;
  }
  
  /* adjust parent item down arrow position */
  .et_vertical_nav #main-header #top-menu > li > a:after {
    right: 0px;
  }
  
  /* adjust lower level parent item down arrow position */
  .et_vertical_nav #top-menu li .menu-item-has-children>a:first-child:after {
    right: 10px;
  }
  
  /* decrease the submenu item left and right padding */
  #top-menu li li {
    padding: 0 10px;
  }
  
  /* adjust submenu item link width and padding */
  #top-menu li li a {
     	width: auto;
     	padding: 6px;
  }
  
  /* remove right border and adjust positioning of the right vertical menu submenu */
  .et_vertical_nav.et_vertical_right #main-header #top-menu li ul {
    right: 0;
    border-right-width: 0;
  }
  
}
Add this CSS either into the Custom CSS field on Divi -> Theme Options page or to you child theme style.css file and save.

Adding JS

After applying the CSS provided above we have moved submenus underneath their parent menu items but they are not visible since we’ve hid them because they need to be closed on initial page load.

Next we have to make the submenus expand and collapse when we click the parent menu items. To do that we’ll use the following code snippet:

<script type="text/javascript">
  
  (function($){
    function collapse_vertical_menu_submenus() {
      
      var $menu = $('#top-menu'),
        top_level_link = '#top-menu .menu-item-has-children > a';

      $menu.find('a').each(function() {
        $(this).off('click');

        if ( $(this).is(top_level_link) ) {
          $(this).attr('href', '#');
        }

        if ( $(this).siblings('.sub-menu').length ) {
          $(this).on('click', function(event) {
            event.preventDefault();
            $(this).siblings('.sub-menu').slideToggle();
          });
        }
      });
    }

    $(window).load(function() {
      collapse_vertical_menu_submenus();
    });

  })(jQuery);
  
</script>
Add this JS into the Add code to the < head > of your blog field in Divi -> Theme Options page Integration tab, save and you’re done!

If you want to show and hide the Divi Vertical Navigation on click then you might want to check out this tutorial: Show and Hide Divi Vertical Navigation on Click , they work very well with each other.

Adjustments for the Divi Desktop Menu Customizer plugin

If you are using the Divi Desktop Menu Customizer plugin, you need to add the following CSS as well (in addition to the CSS provided above):
/* Adjustments for DMC plugin */
@media all and (min-width: 981px) {
  #main-header #top-menu li ul {
    -webkit-transition: none !important;
    -o-transition: none !important;
    transition: none !important;
  }
  .chi_dmc_default.et_vertical_nav:not(.et_vertical_right) #main-header #top-menu > li > ul,
  .chi_dmc_default.et_vertical_nav:not(.et_vertical_right) #main-header.et-fixed-header #top-menu > li > ul,
  .et_header_style_centered.et_vertical_nav:not(.et_vertical_right) #main-header #top-menu > li > ul,
  .et_header_style_centered.et_vertical_nav:not(.et_vertical_right) #main-header.et-fixed-header #top-menu > li > ul {
    left: 0 !important;
  }
  .chi_dmc_default.et_vertical_nav.et_vertical_right #main-header #top-menu > li > ul,
  .chi_dmc_default.et_vertical_nav.et_vertical_right #main-header.et-fixed-header #top-menu > li > ul,
  .et_header_style_centered.et_vertical_nav.et_vertical_right #main-header #top-menu > li > ul,
  .et_header_style_centered.et_vertical_nav.et_vertical_right #main-header.et-fixed-header #top-menu > li > ul {
    right: 0 !important;
  }
  .chi_dmc_default.et_vertical_nav #main-header #top-menu li ul ul,
  .chi_dmc_default.et_vertical_nav #main-header.et-fixed-header #top-menu li ul ul,
  .et_header_style_centered.et_vertical_nav #main-header #top-menu li ul ul,
  .et_header_style_centered.et_vertical_nav #main-header.et-fixed-header #top-menu li ul ul {
    left: 0;
  }
  .chi_dmc_default.et_vertical_nav.et_vertical_right #main-header #top-menu li li ul,
  .chi_dmc_default.et_vertical_nav.et_vertical_right #main-header.et-fixed-header #top-menu li li ul,
  .et_header_style_centered.et_vertical_nav.et_vertical_right #main-header #top-menu li li ul,
  .et_header_style_centered.et_vertical_nav.et_vertical_right #main-header.et-fixed-header #top-menu li li ul {
    right: 0;
  }
  .chi_dmc_default #main-header #top-menu li:not(.mega-menu) li a,
  .chi_dmc_default #main-header.et-fixed-header #top-menu li:not(.mega-menu) li a,
  .et_header_style_centered #top-menu li:not(.mega-menu) li a,
  .et_header_style_centered #main-header.et-fixed-header #top-menu li:not(.mega-menu) li a {
    width: auto;
  }
  .chi_dmc_default.et_vertical_nav #main-header #top-menu li ul ul,
  .chi_dmc_default.et_vertical_nav #main-header.et-fixed-header #top-menu li ul ul,
  .et_header_style_centered.et_vertical_nav #main-header #top-menu li ul ul,
  .et_header_style_centered.et_vertical_nav #main-header.et-fixed-header #top-menu li ul ul {
    top: 0;
  }
}
/* END Adjustments for DMC plugin */

That’s all, hope you’ll find this tutorial useful. Share it with your friends and feel free to leave your thoughts and suggestions in the comments section below and subscribe to stay updated ;)

View Live Demos & Get Divi MadMenu

    Download FREE Divi Sections

      45 Comments

      1. Janik

        Hello,

        would you tell us how to use this for a normal menu modul (divi theme)?

        this will be great :)

        Reply
        • Ivan

          Hi Janik.

          This code works with the Divi theme default Vertical navigation only. You could make it work for the menu created using the Divi Menu module though, for that you’d need to update the selectors in the JS and CSS snippets accordingly and probaby use a little bit more CSS to create the vertical menu layout because the Menu module does not provide a Vertical menu layout option.

          Reply
      2. peaceharbor

        Anyone else having an issue with an iPad landscape display working properly? The menu won’t expand easily on its own, and if it does it’s really sluggish. Otherwise, this works wonderfully.

        Reply
      3. Mike

        Hi Ivan,

        Any idea how to implement your code to this vertical menu?
        elegantthemes.com/blog/divi-resources/how-to-create-a-vertical-navigation-menu-or-header-for-your-divi-website

        I wonder to have vertical menu only on specific pages.

        Thank you,

        Regards,
        Mike

        Reply
      4. Pernille

        Beginner question :-)

        I have copied the css and js script into the divi theme.

        I then create a left menu under appearance in Divi – but what name shall I write in css class to get the submenu to work? Or is’nt it the way to go?

        Reply
        • Ivan Chi

          Hi Pernille.

          You don’t need to add any CSS classes, just follow the instructions and it will work, you only need to add the provided CSS and JS code.

          Reply
          • Brett

            I think there is an implicit assumption to your tutorial. I can’t make it work with a Divi menu module that is added in the body of the page. It seems like I need to link the CSS and Java to a “top menu,” but I don’t know what a “top menu” is . . . when I added the Java and the CSS as indicated, the Divi Menu Module did not respond.

            Reply
            • Ivan

              Hi Brett.

              This tutorial is for Divi’s Vertical Navigation, it’s mentioned in the very first sentence of the tutorial and is marked with bold :). So, it’s not supposed to work with Divi Menu module, you can use this tutorial only if you use Divi theme’s native(legacy) header with the Vertical layout enabled in Divi Theme Customizer.

              Reply
      5. Ioannis

        Hello Ivan, This is a great post and it help me to make a vertical menu like I was imagine!
        I need something more to complete my vertical menu. I want the menu to scroll up. If you see now the submenu in the following domain: alexandraanagnostopoulou.com, it is scroll down. I would like the menu to be in the bottom of the page(I can do that with css: padding-top: 200px) and the submenu to scroll up. How can I do that?
        Thank you in advance!

        Reply
        • Ioannis

          I want to make a correction. When I say the menu to scroll up, I mean the menu to expand up, not down.

          Reply
          • Ivan Chi

            Hi Ioannis.

            Check out the CSS in this tutorial for the bottom positioned mobile dropdown menu which expands upwards, might be helpful.

            Reply
            • Ioannis

              Finally, I managed to do it with a easiest way. I used only one line of css in two places and done!: transform: rotateX(180deg);
              You can check the menu here: alexandraanagnostopoulou.com

              Reply
      6. Hector

        Hello Ivan,
        Thank you very much. Your posts are really helping me big time.
        I’ve read every question and answer in this one, and I’m trying to achieve something for days now, but I can’t figure it out.

        I have a two items menu, where I want to keep one of them showing all the submenus by default. And the other one not.

        I changed this in your code, so it makes it show the submenus by default:

        .et_vertical_nav #main-header #top-menu li ul {
        display: block;
        visibility: visible;
        }

        Then I applied a class to the parent I don’t want to show by default (.notShow), and set:
        .notShow ul {
        display: none;
        }

        But this makes the children invisible. I’ve also tried the other way around. I mean, instead showing everything and hiding what I don’t want to show. I hide everything, and only show what the menu I want to, but it makes also show the subchildren.

        Hope I made myself clear. Any thoughts?

        Reply
      7. BenoitS

        Hi Ivan,
        That’s a really good tuto, thanks a lot.
        I have one question, do you know how to automatically close the menu with an outside click?
        After clicking on my menu and showing my sub menu, if I click anywhere in the page I would like this action to close the menu.
        Thanks

        Reply
        • Kris

          That’s what I’m currently struggling with, can’t nail it.

          Reply
      8. Jonathan

        Thanks for posting this! Any idea how I might integrate a smooth scroll to each page item?

        Reply
      9. Tom

        Hi Ivan,
        I’m using your script and all is working fine except on a tablet in landscape format – The toggle links don’t open/close the menu. Touching longer gives me the system options ‘Open’, Open in new Tab’ etc. and on ‘Open’ the toggle works.
        Is there a way to fix that? Thank you for any idea. Tom

        Reply
        • Ivan Chi

          Hi Tom,

          check the Console for any JS errors.

          Reply
      10. Hector

        Hello Ivan.
        Great work! It helps me a lot.

        I’ve been trying to tweak your code to make it suit my needs, but I can’t figure it out.

        I actually want it to show the first level of submenus by default, which I acomplished by changing display from “none” to “block”. But that makes it show the second level too, which I want to keep hidden till the user click it.

        I’ve defined a class called “hidden_menu” and I have applied it to the second level of submenus. Then I hid them using “display:none”. It actually hides them, but if you click on it, It won’t show anything.

        Many thanks in advance.

        Reply
        • Ivan Chi

          Hi Hector.
          Try this:


          .et_vertical_nav #main-header #top-menu > li > ul {
          display: block;
          }

          It will set the display:block for the first level submenu only.

          Reply
      11. mertxe

        Just commenting tu say thank you! You saved me!

        Reply
        • Ivan Chi

          You are welcome, I’m glad it helped :)

          Reply
      12. Thierry

        Awesome
        ….great, thank you very much ….

        Reply
      13. Ahmad Fadhuli Rozaki

        I have one inquiry, i want to auto collapse one submenu when i expand other submenu.

        Reply
        • Ivan Chi

          Hi Ahmad,

          you can do that easily with a few additional lines of jQuery code. Add these lines into the collapse_vertical_menu_submenus() function after the event.preventDefault() line (after line 18) :


          current_submenu = $(this).siblings('.sub-menu');
          current_submenu_parents = current_submenu.parents('.sub-menu');
          $(this).parents('#top-menu').find('.sub-menu').not(current_submenu_parents).not(current_submenu).slideUp();

          This will make all other open submenus close on click except for the current submenu and its parent submenus if it is a nested submenu.

          Reply
      14. ramon

        Very useful! Thank you very much for your code Ivan!

        but I need your help …

        I want to do the same as Adriana and Patrick, I want the menus to be always closed but if I open any of them, then that menu “remember” its opened position while I browse through the pages.

        If I write display: block; shows all the menus open.
        If I write display: none; shows all the menus closed.

        So I need a “mix” between both options… I mean, I need each menu to keep its position (opened or closed) while I browse the web.

        Thanks!

        Reply
        • Ivan Chi

          Hi ramon,

          add this line into the collapse_vertical_menu_submenus() function:

          // keep submenu open if it has an active item
          $('.sub-menu .current-menu-item').parents('.sub-menu').show();

          Hope this helps.

          Reply
          • ramon

            Amazing Ivan! Thanks a million!

            and of course, I really recommend your plugins:

            · Divi Desktop Menu Customizer
            · Mobile Menu Customizer

            Cheers!

            Reply
            • Ivan Chi

              Thank you, Ramon. Glad to be helpful :)

              Reply
      15. Raj

        Hi Ivan!

        Great tutorial and thanks for sharing! I am new in coding and don’t fully understand your javascript. My top_menu should still be clickable – how can I fix that?

        BR
        Raj

        Reply
        • Ivan Chi

          Hi Raj,

          do you mean the parent menu items are not clickable? Well, this is the limitation of the approach provided in this tutorial, it disables the parent menu items and clicking on them only expands/collapses the submenu.
          A different approach is needed to keep the parent menu items clickable and the arrow to expand/collapse the submenu.

          Reply
          • raj

            Hi Ivan,

            Oh oke! Thanks for your quick reply.

            BR

            Reply
            • Reg

              Hello Raj!
              Have you found a solution to this issue?

              Reply
          • Sven Frank & Elke Schuster GbR

            Hello Ivan,

            great tutorial – many thanks for this!

            But currently I’m stuck at exactly this problem: open sub-menu on click but keep the parent clickable as well.

            You mentioned a different approach in your answer. Could give me some hints, how to achieve this?

            Thanks!

            Reply
      16. Patrick Freden

        Hey Ivan….what will I need to do to keep the menu open from page to page and display the active link or page I am now on?…example when you visit the site click COMMERCIAL REAL ESTATE > EAST TEXAS > MEDICAL….once you are on the Medical page the menu has collapsed

        I am still in development but so far I am very happy with your tutorial (big life safer for me)

        Thank you in advance for your time.

        Sincerely,
        Patrick

        Reply
        • Patrick Freden

          Hey Ivan….still looking for some help…website is much further along now too!…any help or guidance would be a big help…I’d like the menu to stay open to the last page clicked…COMMERCIAL REAL ESTATE > EAST TEXAS > MEDICAL…you are now on Medical page and I’d like the menu to stay open…acts like breadcrumbs in a way.

          Thanks again!
          P

          Reply
          • Raj

            Hi Patrick

            See his answer to Adrianas question :)
            Change in your CSS file – display: none to display: block

            BR

            Reply
      17. Paul

        Ivan privet!

        If someone have no intention to change own current styles just add only display: none; (line 4). This also just might work out for the best.

        Thanks for JS.

        Reply
        • Ivan Chi

          Hi Paul :)

          Actually, adding only the display:none won’t be enough because, for example, by default the submenus have the position:absolute with top, left and right offsets which need to be addressed as well, and some other adjustments need to be done to make it work smoothly.

          But, of course, part of the CSS provided is for styling purposes, like removing too much of margin and padding which leave very little space for submenu links making them look ugly. Each of the CSS snippets is commented for you to know what it does so that you could see whether you need it or not.

          Reply
      18. Adriana Zambrano

        Hi, great, but my menu appear open. Is possible every item is close till I click on?

        Reply
        • Ivan Chi

          Hi Adriana,
          did you apply any other custom CSS to your vertical menu submenus which sets the submenus to display:block? For the submenus to be hidden by default they need to be set to display:none but in your case looks like they are still being set to display:block.

          Reply
      19. Will

        This is good, but the animation of the submenu is a bit glitchy. When you click the menu item, the submenu doesn’t open smoothly. Is there a way to fix this?

        Reply
        • Ivan Chi

          Hi Will,
          it should be smooth as you can see in the demo preview video above. Probably there is a conflict with some other code but it is hard to tell exactly what is causing the glitch without a url.

          Reply
          • John Y

            Hi Ivan, thanks for the work you provided but it is glitchy on my site too. I’ve used no other plugins, code or anything else this is the first thing I did once I set up the menu. It lags when you open or close the submenu for about half a second on any browser, and doesn’t look as smooth as in the vid you provided above. Thanks in advance for your time.

            Reply
            • Ivan Chi

              Hi John,

              yes, you’re right, the animation is lagging and the reason is that there is a conflict with the default transition applied to submenus on hovering over the parent menu items. Actually, I’d noticed that issue and fixed it before I recorded the demo preview but then somehow forgot to include the fix into the final CSS. It can be fixed by setting the transition: none; for submenus.

              I have updated the CSS accordingly, copy it and try again.

              Reply

      Submit a Comment

      Your email address will not be published. Required fields are marked *

      Get FREE Divi Layouts

      Download 20+ Divi templates for FREE!

      Please confirm your email address to complete your subscription. Thank you!

      Copy link