Ariona Rian Ariona Rian - 1 year ago 63
Javascript Question

Expanding hover area to outside element

I have a dropdown menu, which the sub-menu placed on different element. So basically when the mouse leave the menu item, the sub-menu get closed immediately because the sub-menu is not the child.

var menuItem = $(".menu-item");

menuItem.hover(hoverIn, hoverOut);

function hoverIn() {
var mnItemMeta = $(this)[0].getBoundingClientRect();

opacity: 1,
left: mnItemMeta.left

function hoverOut() {
opacity: 0

html,body{background-color: #efefef;}
.menu {
list-style: none;
padding-left: 0;
display: flex;
justify-content: center;
a {
display: block;
padding: 10px 20px;
text-decoration: none;
color: inherit;
.sub-menu {
opacity: 0;
background-color: white;
position: absolute;
transition: .2s ease;
.sub-menu-list {
list-style: none;
padding-left: 0;

<script src=""></script>
<ul class="menu">
<li class="menu-item"><a href="#">Menu Item</a>
<div class="sub-menu">
<ul class="sub-menu-list">
<li><a href="#">Sub Menu 1</a>
<li><a href="#">Sub Menu 2</a>
<li><a href="#">Sub Menu 3</a>
<li><a href="#">Sub Menu 4</a>

The question is how to extend the hover area, so when the cursor point into sub-menu it ignore the hoverOut action.

NOTE: don't tell me to place the sub-menu inside the menu-item, i already how that worked. It's for different case that need the sub-menu to be placed outside the menu-item. thanks :)

Answer Source

Okay, i have figured the solution. Thanks to all of you for giving some advice, but I can't accept the answers from you guys since the solution need more workaround.

So, basically a i created two function, which is startCloseTimeout() and stopCloseTimout(), and bind it on both menu-item and submenu.

Here is the function itself:

var startCloseTimeout = function (){
    closeDropdownTimeout = setTimeout( () => closeDropdown() , 50 );

stopCloseTimeout   = function () {
    clearTimeout( closeDropdownTimeout );

And here is how i bind to mouse events:

//- Binding mouse event to each menu items
menuItems.forEach( el => {

    //- mouse enter event
    el.addEventListener( 'mouseenter', function() {
        openDropdown( this );
    }, false );

    //- mouse leave event
    el.addEventListener( 'mouseleave', () => startCloseTimeout(), false);

} );

//- Binding mouse event to each sub menus
menuSubs.forEach( el => {

    el.addEventListener( 'mouseenter', () => stopCloseTimeout(), false );
    el.addEventListener( 'mouseleave', () => startCloseTimeout(), false );

} );

So, how this code work?

By creating close timeout handler we can control when the dropdown should close or not.

When the mouse is entering the menu-item this is what happen: 1. Stop current running closeDropdownTimout 2. Open related dropdown menu

when the mouse is leaving the menu-item it start the closeDropdownTimout.

But how the dropdown menu still open? Since we set the same action on dropdown menu, the closeDropdownTimout well be cleared and canceling the close action.

For full source code you can check it out on codepen