Simple Mega Menus with Beaver Builder and Beaver Themer
Heads Up!
We turned the below code into another awesome tool and chucked it into Beaver Team Pro. Plus we added keyboard navigation for accessibility and an even simpler configuration! Check out the Video on the Mega menu update.
Dont worry, the code below still works great.
I played with a million mega menu plugins over the years and they were all to complex or too simple to make it look good. So I ended up building my own.
These snippets of CSS/JS are all you need to add to your BB/Themer website to create awesome Mega Menus
Watch the video, and then steal the code :)
How it Works
- Add the ID my-mega-menu to your Beaver Builder menu.
- Create a Beaver Themer part, make it visible on the entire site.
- Create Rows inside the Themer part
- For each menu item, create a Row and give the row a special ID. this is where the code does its magic
- The code takes the menu item name, and looks for a lowercase version, with dashes for spaces, starting with "mega-"
- Contact Us menu item would have an associated mega menu ID of mega-contact-us
- About maps to mega-maps
- Services -> mega-services
- The code does the rest.
- For each menu item, create a Row and give the row a special ID. this is where the code does its magic
The JS:
To add JS sitewide:
- Open any page with Beaver Builder
- Click the title bar in the upper left corner to open the Tools menu, then click Global settings.
- On the JavaScript tab, enter this JavaScript code.
- Click Save.
// mega menu js
var menuElement = "#my-mega-menu .menu-item";
var mobileToggle = '.fl-menu-mobile-toggle';
jQuery(document).ready(function(){
// exit if bb is running
if(jQuery('body').hasClass('fl-builder-edit'))
return true;
//add the helper parent class to the mega menu for mobile
jQuery('[id^="mega-"]').first().parent().addClass('mega-mobile-container')
//set top location of
jQuery(window).on('resize', function () {
if(isMobile())// set init value
{
//set top value of container
topValue = jQuery(mobileToggle).offset().top + jQuery(mobileToggle).outerHeight();
jQuery('.mega-mobile-container').css('top',topValue + 'px');
}
else
{
jQuery('.mega-mobile-container').css('top','');
jQuery('.show-mega-mobile').removeClass('show-mega-mobile');
topValue = 0;
}
jQuery(menuElement).each(function(){
var menuItem = jQuery(this);
var megaItem = jQuery("#"+"mega-"+menuItem.text().replace(/\s/g , "-").toLowerCase());
if(megaItem.length) // if its mega anything
{
//set up hover listeners for menu items
menuItem.hover(function() {
if(!isMobile())
{
jQuery("#"+"mega-"+jQuery(this).text().replace(/\s/g , "-").toLowerCase()).addClass('show-mega');
}
}, function() {
if(!isMobile())
{
jQuery("#"+"mega-"+jQuery(this).text().replace(/\s/g , "-").toLowerCase()).removeClass('show-mega');
}
});
//the rest should be handled with CSS
if(isMobile())
{
megaItem.css('top', topValue + 'px');
topValue += megaItem.height();
}
else
{
jQuery('body').removeClass('show-mega-mobile');
topValue = menuItem.offset().top + menuItem.outerHeight();
megaItem.css('top', topValue + 'px');
}
}
});
}).resize();
jQuery(mobileToggle).click(function(event){
event.preventDefault();
event.stopPropagation();
jQuery('body').toggleClass('show-mega-mobile');
});
});
function isMobile(){
return jQuery(mobileToggle).is(':visible');
}
The CSS:
To add CSS sitewide:
- Open any page with Beaver Builder
- Click the title bar in the upper left corner to open the Tools menu, then click Global settings.
- On the CSS tab, enter this CSS code.
- Click Save.
body:not(.fl-builder-edit) [id^="mega-"] {
-webkit-transition: all 300ms ease-in-out;
-moz-transition: all 300ms ease-in-out;
-ms-transition: all 300ms ease-in-out;
-o-transition: all 300ms ease-in-out;
transition: all 300ms ease-in-out;
z-index: 100;
}
.show-mega{
visibility: visible !important;
opacity: 1 !important;
}
body:not(.fl-builder-edit) [id^="mega-"]:hover {
visibility: visible !important;
opacity: 1 !important;
}
/* mobile stuffs */
body.show-mega-mobile [id^="mega-"]{
visibility: visible !important;
opacity: 1 !important;
}
/* small screens mega settings*/
@media (max-width: 767px){
.mega-mobile-container{
visibility: hidden;
opacity: 0;
position: fixed;
top:150px;
left: 0;
bottom: 0;
overflow-y: scroll;
width: 100%;
z-index: 100;
}
.show-mega-mobile .mega-mobile-container{
visibility: visible !important;
opacity: 1 !important;
}
}
/* bigger screens mega settings*/
@media (min-width: 768px){
body:not(.fl-builder-edit) [id^="mega-"] {
visibility: hidden;
opacity: 0;
position: fixed;
top:150px;
left: 0;
width: 100%;
}
}
18 Comments
Leave a Comment
Level up your Beaver Builder skills
Join 3,264 Beaver Builders and get our monthly-ish dish
We've got a million ideas that we've implemented on over 300+ BB enabled websites. Pop in your email below, and we'll let you know when a new post or plugin is available :)
Newsletter
"*" indicates required fields
Spam sucks.
Hey there! I love this! So much simpler than some of those menus like Quad Menu.
Any chance to consider revealing the dropdown on a click?
https://css-tricks.com/in-praise-of-the-unambiguous-click-menu/
Thanks Ben!
When you’re right, you’re right. I’ll update the code in the next few days for the unambiguous click.
Hi Tom.
This is an excellent solution, thank you.
I have a slight issue in that some of my menu items contain a question mark, which stops the mega menu from working.
Is there any chance you could update the JS to allow for this please.
Also noticed another issue, I’m getting a gap above each subsequent mega menu…
Here is a short clip of the issue – https://cln.sh/uFpkhDG1xdAURei758qI
Unfortunately the site is only on local at the moment, but if you need any further info I can provide it.
Thanks Craig!
I’ve updated the code to replace all non alphanumeric characters, so your ?’s and !’s should now be replaced with a single “-”
Just FYI, the code is also updated to on click now, its much better UX than “on hover” 🙂
I added the helper function megaDebug() so you can see what your mega menu row ID’s should be after being parsed. Just type megaDebug() into the console, and it will tell you the mega names.
As for the other issue – I can’t really say without seeing it live. Its a good looking site though! Push it onto a server and send me a link, we’ll get it working for you 🙂
Wow! That’s fantastic Tom. Thank you.
I have emailed you separately with a link and another query.
Best regards,
Craig
This is fantastic! I have been wanting to do just this on a few sites but didn’t have the time or brains to work it out — super excited!
Awesome! Please share some links to some completed sites!
Hi Tom –
Fantastic contribution. Thanks!
I have a small issue. See:
https://vsbbusdir.wpengine.com/
PLAN YOUR TRIP is the mega row and it works great…
Except when you are on an actual directory listing.
example:
https://vsbbusdir.wpengine.com/business-listing/celebration-cruises/
Now the click doesn’t load the menu rows.
Can you take a quick look and help me figure it out?
I am also using the Max Width columns plugin and it too is a great and very much appreciated solution.
Hi Tom,
I was using another Mega Menu solution and then found out that it’s really not accessible (specifically via keyboard navigation). Was wondering if your solution here is and if that includes any content in the menu or if it’s only links/button. I.e. if you tab to the top menu item the menu opens, and then you can tab/arrow through all the items in the menu before you tab on to the next top menu item, and so on?
Hey Greg!
This is not accessible as it stands but our next update will be specifically to make it *more* accessible – but definitely not perfect.
Hi Again Greg – If you want an accessible mega menu with keyboard nav, check out the Mega menu module in Beaver Team Pro. 🙂
I love this mega-menu but I”m having a major problem with it and I can’t figure out a solution.
When I load a page, the mega-menu isn’t visible but it’s sitting behind the regular content just below the menu and the items in my menu are still clickable. This interferes with other interactivity on the page. I would assume that the mega-menu should be positioned off-canvas until it’s needed?
Great tutorial! Just curious what the JS was to make the menu apper on hover.
Love this, but appear to have a problem with too many spaces…
“How We Help” is being offered as “mega-how-we help”
See screenshot – https://snipboard.io/TtEO3V.jpg
I’ve noticed that if I have a menu item that links to an anchor on the current page, the menu doesn’t disappear. Wondering if the code should hide the megamenu on *any* click.
I tried replacing this IF statement:
//click outside of mega menu
jQuery(document).on(‘click’, function (e) {
if (jQuery(e.target).closest(‘[id^=”mega-“], .mega-mobile-container’).length === 0) {
if(jQuery(‘.show-mega, .show-mega-mobile’).length){
jQuery(‘[id^=”mega-“]’).removeClass(‘show-mega’);
jQuery(‘body’).removeClass(‘show-mega-mobile’);
}
}
});
with this:
//click outside of mega menu
jQuery(document).on(‘click’, function (e) {
if(jQuery(‘.show-mega, .show-mega-mobile’).length){
jQuery(‘[id^=”mega-“]’).removeClass(‘show-mega’);
jQuery(‘body’).removeClass(‘show-mega-mobile’);
}
});
It works, although I suspect there’s probably a better way.
Working nice! However I face an issue on menu items that have some unicode characters (language specific) – in my case Polish (ż, Ä…, Å‚). Any help in modifying the JS code to accommodate that?
is Mobile Function wasn’t working for me so I switched it up a bit…
// mega menu js
// with love from https://sitespot.dev/simple-mega-menus-with-beaver-builder-and-beaver-themer/
var menuElement = “#my-mega-menu .menu-item”;
var mobileToggle = ‘.fl-menu-mobile-toggle’;
jQuery(document).ready(function(){
// exit if bb is running
if(jQuery(‘body’).hasClass(‘fl-builder-edit’))
return true;
//add the helper parent class to the mega menu for mobile
jQuery(‘[id^=”mega-“]’).first().parent().addClass(‘mega-mobile-container’)
//set top location of
jQuery(window).on(‘resize megamenurefresh’, function () {
if(isMobile())// set init value
{
//set top value of container
topValue = jQuery(‘header’).offset().top + jQuery(‘header’).outerHeight() – 20;
jQuery(‘.mega-mobile-container’).css(‘top’,topValue + ‘px’);
}
else
{
jQuery(‘.mega-mobile-container’).css(‘top’,”);
jQuery(‘.show-mega-mobile’).removeClass(‘show-mega-mobile’);
topValue = 0;
}
jQuery(menuElement).each(function(){
var menuItem = jQuery(this);
var megaItem = jQuery(“#”+”mega-“+menuTitle(menuItem.text()));
if(megaItem.length) // if its mega anything
{
//set up click listeners for menu items
menuItem.off(‘click’).click(function(event) {
console.log(‘click’);
event.preventDefault();
mm = jQuery(“#”+”mega-“+menuTitle(jQuery(this).text()));
console.log(“#”+”mega-“+menuTitle(jQuery(this).text()));
console.log(isMobile());
console.log(mm.length);
// if it has a mega menu
if(mm.length && !isMobile())
{
console.log(“inside if”);
event.preventDefault();
event.stopPropagation();
if(!mm.hasClass(‘show-mega’))
{
jQuery(‘.show-mega’).removeClass(‘show-mega’);
mm.addClass(‘show-mega’);
}
else
mm.removeClass(‘show-mega’);
}
});
if(isMobile())
{
megaItem.css(‘top’, topValue + ‘px’);
topValue += megaItem.height();
}
else
{
jQuery(‘body’).removeClass(‘show-mega-mobile’);
topValue = jQuery(“header”).offset().top – jQuery(window).scrollTop() +jQuery(“header”).outerHeight();
megaItem.css(‘top’, topValue + ‘px’);
}
}
});
}).resize();
jQuery(mobileToggle).click(function(event){
event.preventDefault(); // stop the inbuilt stuff from stuffin
event.stopPropagation();
jQuery(‘body’).toggleClass(‘show-mega-mobile’);
});
//close mega menu stuff
// escape click
jQuery(document).on(‘keyup’, function(e) {
if (e.key == “Escape”)
{
jQuery(‘.show-mega’).removeClass(‘show-mega’);
jQuery(‘body’).removeClass(‘show-mega-mobile’);
}
});
//click outside of mega menu
jQuery(document).on(‘click’, function (e) {
if (jQuery(e.target).closest(‘[id^=”mega-“], .mega-mobile-container’).length === 0) {
if(jQuery(‘.show-mega, .show-mega-mobile’).length){
jQuery(‘[id^=”mega-“]’).removeClass(‘show-mega’);
jQuery(‘body’).removeClass(‘show-mega-mobile’);
}
}
});
});
//replace menuItem.text().replace(titleRegex,”-“).toLowerCase()
function menuTitle(theText){
// clean it up
theText = theText.replace(/[^0-9a-z]/gi, ‘ ‘).trim().replace(” “,”-“).replace(/-{2,}/g, ‘-‘);
return theText.toLowerCase();
}
function isMobile(){
//console.log(FLBuilderLayoutConfig.breakpoints.small + jQuery(window).width());
var browserWidth = FLBuilderLayoutConfig.breakpoints.small + jQuery(window).width();
if(browserWidth < 991){
return true;
}else{
return false;
}
//return (FLBuilderLayoutConfig.breakpoints.small + jQuery(window).width());
}
function megaDebug(){
jQuery(menuElement).each(function(){
console.log("mega-"+menuTitle(jQuery(this).text()));
});
}