Timothy's Dev Stuff

A collection of code snippets and other developer things.

Better Mobile Submenus in Elementor

The default behavior of submenus on the tablet/mobile view of Elementor menus is to remain open when opening another top-level submenu. I have found that a better behavior would be to collapse any previously opened top-level submenus when opening a different top-level submenu. I wrote the function below to do that; let’s go through it.

Initially, I wrote this in VS Code and pasted into the console to test. Once I had it working, I wrapped it in a jQuery(document).ready() function. However, the event listener was not triggering the function, so I had to change it to the window.addEventListener() function. This works by first assigning the Elementor menu and the menu items that all have submenus to variables. It's important to note that the ids and classes used to select those elements could change, so view the menu on the front-end to get the appropriate ids and classes.

The collapseOpenSubmenus() function takes an element as an argument (that element is the clicked element and is passed by the event listener at the bottom). The passed element is use for a comparison later to make sure it's not collapsing the submenu you just expanded. Then we loop through all of the elements with submenus (referred to as currentIndex).

The first if-statement jumps up a couple of elements and makes an id comparison. If the id matches the Elementor menu id, then the current index is a top-level item. If it fails this check, then it could be a nested submenu and gets skipped. Next we make sure the current index is not the submenu we just clicked (the one that called the function). If not, we can then check the current index to see if it is expanded. If it is expanded, we can go down to the first child element (the <span>) and simulate a click on that.

The reason I went down to the span is because if we clicked the current index, the anchor tag, we would essentially be clicking that link and navigating to that page. It was through trial and error that I figured out the child element could be clicked to get the effect I wanted.

Last, we add a click listener to the menu items and run the function, passing the jQuery(this) element.

window.addEventListener("load", () => {

    const elementorMenu = jQuery("[id^='menu-2']");
    const menuItemsWithSubmenu = jQuery("a.elementor-item.has-submenu");

    function collapseOpenSubmenus(element) {
        let clickedElement = jQuery(element);

        menuItemsWithSubmenu.each(function (currentIndex) {

            // If the menu item is top level
            if (jQuery(menuItemsWithSubmenu[currentIndex]).parent().parent().id == elementorMenu.id) {

                // If it is NOT the clicked (passed) element
                if (jQuery(menuItemsWithSubmenu[currentIndex]) != clickedElement) {

                    // If it is expanded
                    if (jQuery(menuItemsWithSubmenu[currentIndex]).attr("aria-expanded") == "true") {
                        jQuery(menuItemsWithSubmenu[currentIndex]).children()[0].click();
                    }
                }
            }
        });
    }

    menuItemsWithSubmenu.click(function () {
        collapseOpenSubmenus(jQuery(this));
    });
});