I’m trying to make Magento menu open categories only on click and disable hover function. It opens subcategories but once you open a subcategory it doesn’t collapse and you can’t expand a different subcategory
I added in app/design/frontend/Vendor/theme/require-config.js the following code
var config = {
config: {
mixins: {
'mage/menu': {
'Magento_Theme/js/menu-mixin': true
}
}
},
};
Then, in app/design/frontend/Vendor/theme/Magento_Theme/web/js I’ve added the following script:
define([
'jquery',
],
function ($) {
return function () {
$.widget('mage.custommenu', $.mage.menu, {
_toggleDesktopMode: function () {
var html, subMenus;
$(this.element).off('click mousedown mouseenter mouseleave');
this._on({
/**
* Prevent focus from sticking to links inside menu after clicking
* them (focus should always stay on UL during navigation).
*/
'mousedown .ui-menu-item > a': function (event) {
event.preventDefault();
},
/**
* Prevent focus from sticking to links inside menu after clicking
* them (focus should always stay on UL during navigation).
*/
'click .ui-state-disabled > a': function (event) {
event.preventDefault();
},
/**
* @param {jQuer.Event} event
*/
'click .ui-menu-item:has(a)': function (event) {
var target = $(event.target).closest('.ui-menu-item');
if (!this.mouseHandled && target.not('.ui-state-disabled').length) {
this.select(event);
// Only set the mouseHandled flag if the event will bubble, see #9469.
if (!event.isPropagationStopped()) {
this.mouseHandled = true;
}
// Open submenu on click
if (target.has('.ui-menu').length) {
this.expand(event);
} else if ($(this.document[0].activeElement).closest('.ui-menu').length) {
// Redirect focus to the menu
this.element.trigger('focus', [true]);
// If the active item is on the top level, let it stay active.
// Otherwise, blur the active item since it is no longer visible.
if (this.active && this.active.parents('.ui-menu').length === 1) { //eslint-disable-line
clearTimeout(this.timer);
}
}
}
subMenus = this.element.find('.level-top');
$.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.__('%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));
},
/**
* @param {jQuery.Event} event
*/
'click .ui-menu-item.parent': function (event) {
var target = $(event.target).closest('.ui-menu-item');
if ($(target).hasClass('parent')) {
event.preventDefault();
}
var target = $(event.currentTarget),
submenu = this.options.menus,
ulElement,
ulElementWidth,
width,
targetPageX,
rightBound;
if (target.has(submenu)) {
ulElement = target.find(submenu);
ulElementWidth = ulElement.outerWidth(true);
width = target.outerWidth() * 2;
targetPageX = target.offset().left;
rightBound = $(window).width();
if (ulElementWidth + width + targetPageX > rightBound) {
ulElement.addClass('submenu-reverse');
}
if (targetPageX - ulElementWidth < 0) {
ulElement.removeClass('submenu-reverse');
}
}
// Remove ui-state-active class from siblings of the newly focused menu item
// to avoid a jump caused by adjacent elements both having a class with a border
target.siblings().children('.ui-state-active').removeClass('ui-state-active');
this.focus(event, target);
},
/**
* @param {jQuery.Event} event
*/
'click .ui-menu-item': function (event) {
var target = $(event.target).closest('.ui-menu-item');
if ($(target).hasClass('level0')) {
return;
}
var target = $(event.currentTarget),
submenu = this.options.menus,
ulElement,
ulElementWidth,
width,
targetPageX,
rightBound;
if (target.has(submenu)) {
ulElement = target.find(submenu);
ulElementWidth = ulElement.outerWidth(true);
width = target.outerWidth() * 2;
targetPageX = target.offset().left;
rightBound = $(window).width();
if (ulElementWidth + width + targetPageX > rightBound) {
ulElement.addClass('submenu-reverse');
}
if (targetPageX - ulElementWidth < 0) {
ulElement.removeClass('submenu-reverse');
}
}
// Remove ui-state-active class from siblings of the newly focused menu item
// to avoid a jump caused by adjacent elements both having a class with a border
target.siblings().children('.ui-state-active').removeClass('ui-state-active');
this.focus(event, target);
},
});
html = $('html');
if (html.hasClass('nav-open')) {
html.removeClass('nav-open');
setTimeout(function () {
html.removeClass('nav-before-open');
}, this.options.hideDelay);
}
},
focus: function () {
return false;
},
});
return $.mage.custommenu;
}
});
Finally, I’ve updated topmenu.phtml file in app/design/frontend/Vendor/theme/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 MagentoThemeBlockHtmlTopmenu
*/
$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":true, "position":{"my":"left top","at":"left bottom"}}}'>
<?= /* @noEscape */ $_menuHtml ?>
<?= $block->getChildHtml() ?>
</ul>
</nav>