Skip to content

Instantly share code, notes, and snippets.

@Garconis
Last active April 3, 2023 10:02
Show Gist options
  • Star 19 You must be signed in to star a gist
  • Fork 13 You must be signed in to fork a gist
  • Save Garconis/a3855dbd7bfb7eeaebe1601d11b33979 to your computer and use it in GitHub Desktop.
Save Garconis/a3855dbd7bfb7eeaebe1601d11b33979 to your computer and use it in GitHub Desktop.
Divi | WordPress Theme | Mobile Menu Collapsible Submenus via Toggles | CSS & jQuery Tweaks in action: https://i.gyazo.com/93557e9ef5d4aad260e22c6d5896de3b.mp4
/* -- HEADER -- */
/* remove pointer event from menu module mobile wrapper */
.et_pb_module.et_pb_menu .et_mobile_nav_menu {
pointer-events: none;
}
/* make menu module hamburger icon and menu links interactive again */
.et_pb_module.et_pb_menu .et_mobile_nav_menu .mobile_menu_bar,
.et_pb_module.et_pb_menu .et_mobile_nav_menu .et_mobile_menu li a {
pointer-events: auto;
}
/* when mobile menu is open, change hamburger icon to x icon */
#et_mobile_nav_menu .mobile_nav.opened .mobile_menu_bar::before,
.et_pb_module.et_pb_menu .et_mobile_nav_menu .mobile_nav.opened .mobile_menu_bar::before {
content: '\4d';
}
/* make desktop sub sub menu icon be right arrow instead of down arrow */
#top-menu .menu-item-has-children .menu-item-has-children > a:first-child::after,
#et-secondary-nav .menu-item-has-children .menu-item-has-children > a:first-child::after,
.et_pb_module.et_pb_menu .et-menu .menu-item-has-children .menu-item-has-children > a:first-child::after {
content: '5';
}
/* if mobile parent link of child menu is a deadlink, then make it not clickable */
#main-header #mobile_menu.et_mobile_menu .menu-item-has-children > a[href="#0"],
.et_pb_module.et_pb_menu .et_mobile_menu .menu-item-has-children > a[href="#0"] {
pointer-events: none;
}
/* - mobile menu toggling elements, injected via jQuery - */
/* make menu list item be relative, to be able to position toggle within this item */
#main-header #mobile_menu.et_mobile_menu .menu-item-has-children,
.et_pb_module.et_pb_menu .et_mobile_menu .menu-item-has-children {
position: relative;
}
/* the new toggle element, which is added via jQuery */
#main-header #mobile_menu.et_mobile_menu .sub-menu-toggle,
.et_pb_module.et_pb_menu .et_mobile_menu .sub-menu-toggle {
position: absolute;
background-color: rgba(0,0,0,0.03);
z-index: 1;
width: 36px;
height: 36px;
line-height: 36px;
border-radius: 50%;
top: 4px;
right: 4px;
cursor: pointer;
text-align: center;
pointer-events: auto;
}
/* the new toggle element when popped */
#main-header #mobile_menu.et_mobile_menu .sub-menu-toggle.popped,
.et_pb_module.et_pb_menu .et_mobile_menu .sub-menu-toggle.popped {
background-color: rgba(0,0,0,0.1);
}
/* toggle icon */
#main-header #mobile_menu.et_mobile_menu .sub-menu-toggle::before,
.et_pb_module.et_pb_menu .et_mobile_menu .sub-menu-toggle::before {
font-family: "ETmodules" !important;
font-weight: normal;
font-style: normal;
font-variant: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
line-height: 36px;
font-size: 24px;
text-transform: none;
speak: none;
content: '\33';
}
/* toggle icon when triggered */
#main-header #mobile_menu.et_mobile_menu .sub-menu-toggle.popped::before,
.et_pb_module.et_pb_menu .et_mobile_menu .sub-menu-toggle.popped::before {
content: '\32';
}
/* hide sub menus by default */
#main-header #mobile_menu.et_mobile_menu .sub-menu-toggle ~ ul.sub-menu,
.et_pb_module.et_pb_menu .et_mobile_menu .sub-menu-toggle ~ ul.sub-menu {
display: none !important;
padding-left: 0;
}
/* show sub menu when triggered via jQuery toggle, and add slight bg color */
#main-header #mobile_menu.et_mobile_menu .sub-menu-toggle.popped ~ ul.sub-menu,
.et_pb_module.et_pb_menu .et_mobile_menu .sub-menu-toggle.popped ~ ul.sub-menu {
display: block !important;
background-color: rgba(0,0,0,0.03) !important;
}
/* remove sub menu list item left padding, since padding will be on anchors */
#main-header #mobile_menu.et_mobile_menu li li,
.et_pb_module.et_pb_menu .et_mobile_menu li li {
padding-left: 0;
}
/* adjust mobile menu anchors side paddings */
#main-header #mobile_menu.et_mobile_menu li a,
.et_pb_module.et_pb_menu .et_mobile_menu li a {
padding-left: 20px;
padding-right: 20px;
}
/* indent sub menu */
#main-header #mobile_menu.et_mobile_menu li li a,
.et_pb_module.et_pb_menu .et_mobile_menu li li a {
padding-left: 40px;
padding-right: 20px;
}
/* indent sub sub menus further */
#main-header #mobile_menu.et_mobile_menu li li li a,
.et_pb_module.et_pb_menu .et_mobile_menu li li li a {
padding-left: 60px;
padding-right: 20px;
}
/* if mobile menu anchor has toggle, make room for it to fit next to the link */
#main-header #mobile_menu.et_mobile_menu .menu-item-has-children .sub-menu-toggle + a,
.et_pb_module.et_pb_menu .et_mobile_menu .menu-item-has-children .sub-menu-toggle + a {
padding-right: 44px;
}
/* - end mobile menu toggling elements - */
/* undo Divi's default styling of mobile menu links that have children */
#main-header #mobile_menu.et_mobile_menu .menu-item-has-children > a,
.et_pb_module.et_pb_menu .et_mobile_menu .menu-item-has-children > a {
background-color: transparent;
font-weight: inherit;
}
/* make the current page's mobile menu link be different */
#main-header #mobile_menu.et_mobile_menu li.current-menu-item > a,
.et_pb_module.et_pb_menu .et_mobile_menu li.current-menu-item > a {
font-weight: bolder;
}
/* -- END HEADER -- */
jQuery( document ).ready( function( $ ) {
// Create collapsible sub menus in mobile Divi Header Nav
$( '<div class="sub-menu-toggle"></div>' ).insertBefore( '#main-header #mobile_menu.et_mobile_menu .menu-item-has-children > a' );
// Create collapsible sub menus in mobile Divi Theme Builder Menu
$( '<div class="sub-menu-toggle"></div>' ).insertBefore( '.et_pb_module.et_pb_menu .et_mobile_menu .menu-item-has-children > a' );
// Toggle the class to be popped on mobile Divi Header Nav
$( '#main-header #mobile_menu.et_mobile_menu .sub-menu-toggle' ).click(function () {
$(this).toggleClass('popped');
});
// Toggle the class to be popped on mobile Divi Theme Builder Menu
$( '.et_pb_module.et_pb_menu .et_mobile_menu .sub-menu-toggle' ).click(function () {
$(this).toggleClass('popped');
});
// Replace the mobile Divi Theme Builder Menu toggle with different href other than # hash, to prevent scroll to top on sub-menu-toggle clicks
$( '.et_pb_module.et_pb_menu a.mobile_nav[href="#"]' ).attr( 'href', '#0' )
} );
@blackbird8552
Copy link

Hi code works great although I have quite a lot of sub menus is it possible to have them closed as currently each main menu item and its sub menus are open. Your assistance would be much appreciated.
Mike

@Azim-Munna
Copy link

thanks man <3 get love from me <3

@rr-gs
Copy link

rr-gs commented Aug 13, 2020

Hello. I really want this to work, but it doesn't.

On this tutorial page https://www.elegantthemes.com/blog/divi-resources/how-to-create-a-mobile-collapsing-nested-menu-with-divis-theme-builder, Sandra says this:

Jon, your solution is exactly what I’m looking for. Unfortunately since the navigations are now built in the theme builder some classes and IDs how now changed from your original code – i.e. #main-header and #top-menu. Any solution for the theme builder, pretty please with a cherry on top ?🙏

Is there any truth to this? Does this need to be updated due to classes and ID names?

@Garconis
Copy link
Author

Any solution for the theme builder, pretty please with a cherry on top ?🙏

Is there any truth to this? Does this need to be updated due to classes and ID names?

@rr-gs yes, this did not work with Theme Builder since they used different classes and structure. I've now updated this and tested on desktop and mobile devices. It should now work for both the regular Divi header menu, and Menu Modules within the Theme Builder.

@rr-gs
Copy link

rr-gs commented Aug 17, 2020

Thanks. I appreciate you going to the effort. It's not working for me. I don't think my site has any of the IDs used in this code, based on searching Console. Something isn't lining up for me. I'll take a closer look, but thanks for doing this.

@rr-gs
Copy link

rr-gs commented Aug 17, 2020

I ended up using this solution:
https://intercom.help/elegantthemes/en/articles/3725736-how-to-create-a-collapsable-mobile-menu-while-keeping-the-parent-links-active

I'm not sure how it lines up with this code, but it worked for me.

@Garconis
Copy link
Author

@rr-gs are you able to share your domain with me to see what the issue may be? I tested in Theme Builder, and it worked fine on a base install with Divi.

@Augustin974
Copy link

Thanks, but that doesn't works for me, i use menu built in theme builder.

@ls-sol
Copy link

ls-sol commented Jul 30, 2021

Oh wow @Garconis, thank you so much for this code.
This is finally the solution that works like I intended. Great job!

I've only got one last questions I couldn't solve so far:
Imagine I'm on a subsite an now open the menu again. Is it possible to open the menu with the active section already opened, so users can see where they currently are?

Thank you so much in advance.

@jason-hub
Copy link

Neither this solution nor https://intercom.help/elegantthemes/en/articles/3725736-how-to-create-a-collapsable-mobile-menu-while-keeping-the-parent-links-active works in the latest version of Chrome for Mac. The +/x icons either make the entire menu collapse when clicked or they don't appear at all.

@gonperes
Copy link

gonperes commented Oct 10, 2022

For the Javascript to work you have to enclose it inside $(document).ready(function () { /* all calls here */ });, because the "ul.et_mobile_menu" element is only appended to the page (by JavaScript/jQuery) after it loads (if you use the Chrome to view the page source you don't see any "ul.et_mobile_menu" element). You could also use setTimeout.

I also removed the "et_pb_menu" class reference from the CSS and JavaScript, because the Divi Theme Builder doesn't use it.

jQuery( document ).ready( function( $ ) {
	
	$(document).ready(function () {
		// Create collapsible sub menus in mobile Divi Header Nav
		$( '<div class="sub-menu-toggle"></div>' ).insertBefore( '#main-header #mobile_menu.et_mobile_menu .menu-item-has-children > a' );
		// Create collapsible sub menus in mobile Divi Theme Builder Menu
		$( '<div class="sub-menu-toggle"></div>' ).insertBefore( '.et_pb_module .et_mobile_menu .menu-item-has-children > a' );


		// Toggle the class to be popped on mobile Divi Header Nav
		$( '#main-header #mobile_menu.et_mobile_menu .sub-menu-toggle' ).click(function () {
			$(this).toggleClass('popped');
		});
		// Toggle the class to be popped on mobile Divi Theme Builder Menu
		$( '.et_pb_module .et_mobile_menu .sub-menu-toggle' ).click(function () {
			$(this).toggleClass('popped');
		});
		// Replace the mobile Divi Theme Builder Menu toggle with different href other than # hash, to prevent scroll to top on sub-menu-toggle clicks
		$( '.et_pb_module a.mobile_nav[href="#"]' ).attr( 'href', '#0' );
	});
} );

@heldopsokken
Copy link

Thanks for sharing your code @Garconis. I fully agree, this should be standard in a payed theme nowadays, I fail to understand why they didnt build this in right away. Anyways youve got us covered. Thanks!

@gonperes
Copy link

gonperes commented Apr 3, 2023

I also removed this CSS code. It was not allowing the menu to scroll if it was too tall and the header was fixed:

/* remove pointer event from menu module mobile wrapper */
.et_pb_module.et_pb_menu .et_mobile_nav_menu {
	pointer-events: none;
}

/* make menu module hamburger icon and menu links interactive again */
.et_pb_module.et_pb_menu .et_mobile_nav_menu .mobile_menu_bar,
.et_pb_module.et_pb_menu .et_mobile_nav_menu .et_mobile_menu li a {
	pointer-events: auto;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment