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' )
} );
@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