By default, magento mobile menu is set to collapse only at the top level and not on all levels. To overcome this default feature one must override the _toggleMobileMode
function that is implemented in the lib\web\mage\menu.js
file.
Overriding or extending javascript functionality in magento should be done using mixins. A mixin is a class whose methods are added to, or mixed in, with another class. Mixins are declared in the mixins
property in the requirejs-config.js
configuration file located in your module’s or theme’s root folder.
In this case we will create a new requirejs-config.js
file under our theme’s root folder: app/design/frontent/<Theme_Vendor>/<Theme_Name>
#File: app/design/frontent/<Theme_Vendor>/<Theme_Name>/requirejs-config.js var config = { config: { mixins: { 'mage/menu': { 'Magento_Theme/js/menu-mixin': true } } }, };
In this file we are saying to magento to use a mixin for the mage/menu
javascript module. This mixin is named menu-mixin.js
and located under app/design/frontent/<Theme_Vendor>/<Theme_Name>/Magento_Theme/web/js
. Note that the web directory is not mentioned in the requirejs-config.js
file but it is added automatically by magento.
Now we need to create the menu-mixin.js
file:
#File: app/design/frontent/<Theme_Vendor>/<Theme_Name>/Magento_Theme/web/js/menu-mixin.js define([ 'jquery', ], function($){ return function() { $.widget('mage.custommenu', $.mage.menu, { _toggleMobileMode: function () { var subMenus; $(this.element).off('mouseenter mouseleave'); this._on({ /** * @param {jQuery.Event} event */ 'click .ui-menu-item:has(a)': function (event) { var target; event.preventDefault(); target = $(event.target).closest('.ui-menu-item'); target.get(0).scrollIntoView(); if (!target.hasClass('parent') || !target.has('.ui-menu').length) { window.location.href = target.find('> a').attr('href'); } }, /** * @param {jQuery.Event} event */ 'click .ui-menu-item:has(.ui-state-active)': function (event) { this.collapseAll(event, true); } }); subMenus = this.element.find('.parent'); $.each(subMenus, $.proxy(function (index, item) { var category = $(item).find('> a span').not('.ui-menu-icon').text(), categoryUrl = $(item).find('> a').attr('href'), menu = $(item).find('> .ui-menu'); this.categoryLink = $('<a>') .attr('href', categoryUrl) .text($.mage.__('All %1').replace('%1', category)); this.categoryParent = $('<li>') .addClass('ui-menu-item all-category') .html(this.categoryLink); if (menu.find('.all-category').length === 0) { menu.prepend(this.categoryParent); } }, this)); } }); return $.mage.custommenu; } });
Because in this file we are just overriding the _toggleMobileMode
, we start by copying the original function to our mixin file to then make the changes we need to implement the required functionality.
If you compare the updated function with the original function you can see that the level-top
selector was replaced by parent
in 2 places: line #25 and line #38.
The last step will be to collapse the menu by default. This is done by overriding the topmenu.phtml
file with the following
#File: app/design/frontent/<Theme_Vendor>/<Theme_Name>/Magento_Theme/templates/html/topmenu.phtml <?php /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /** * Top menu for store * * @var $block \Magento\Theme\Block\Html\Topmenu */ $columnsLimit = $block->getColumnsLimit() ?: 0; $_menuHtml = $block->getHtml('level-top', 'submenu', $columnsLimit) ?> <nav class="navigation" data-action="navigation"> <ul data-mage-init='{"menu":{"responsive":true, "expanded":false, "position":{"my":"left top","at":"left bottom"}}}'> <?= /* @noEscape */ $_menuHtml?> <?= $block->getChildHtml() ?> </ul> </nav>
Note the change to false
in the value of the expanded attribute.
Now you just probably need to make some css changes so it looks great!