Expand and Collapse Divi Vertical Menu Submenus on Click
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; }
/* decrease 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; }
Bringing all of the CSS together
@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; } }
Adding JS
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>
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
/* 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 */
Hello,
would you tell us how to use this for a normal menu modul (divi theme)?
this will be great :)
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.
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.
Hi Ivan,
Any idea how to implement your code to this vertical menu?
https://www.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
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?
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.
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.
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.
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!
I want to make a correction. When I say the menu to scroll up, I mean the menu to expand up, not down.
Hi Ioannis.
Check out the CSS in this tutorial for the bottom positioned mobile dropdown menu which expands upwards, might be helpful.
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
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?
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
That’s what I’m currently struggling with, can’t nail it.
Thanks for posting this! Any idea how I might integrate a smooth scroll to each page item?
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
Hi Tom,
check the Console for any JS errors.
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.
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.Just commenting tu say thank you! You saved me!
You are welcome, I’m glad it helped :)
Awesome
….great, thank you very much ….
I have one inquiry, i want to auto collapse one submenu when i expand other submenu.
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 theevent.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.
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!
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.
Amazing Ivan! Thanks a million!
and of course, I really recommend your plugins:
· Divi Desktop Menu Customizer
· Mobile Menu Customizer
Cheers!
Thank you, Ramon. Glad to be helpful :)
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
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.
Hi Ivan,
Oh oke! Thanks for your quick reply.
BR
Hello Raj!
Have you found a solution to this issue?
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!
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
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
Hi Patrick
See his answer to Adrianas question :)
Change in your CSS file – display: none to display: block
BR
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.
Hi Paul :)
Actually, adding only the
display:none
won’t be enough because, for example, by default the submenus have theposition: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
andpadding
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.Hi, great, but my menu appear open. Is possible every item is close till I click on?
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 todisplay:none
but in your case looks like they are still being set todisplay:block
.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?
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.
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.
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 thetransition: none;
for submenus.I have updated the CSS accordingly, copy it and try again.