How to disable mouseout events triggered by child elements?

How to disable mouseout events triggered by child elements?

Let me describe the problem in details:
I want to show an absolute positioned div when hovering over an element. That’s really simple with jQuery and works just fine. But when the mouse goes over one of the child elements, it triggers the mouseout event of the containing div. How do I keep javascript from triggering the mouseout event of the containing element when hovering a child element.
What’s the best and shortest way to do that with jQuery?
Here is a simplified example to illustrate what I mean:
Html:
Hover Me

Test

Javascript/jQuery:
$(‘a’).hover( function() { $(this).next().show() }
function() { $(this).next().hide() } );

Solutions/Answers:

Solution 1:

The question is a bit old, but I ran into this the other day.

The simplest way to do this with recent versions of jQuery is to use the mouseenter and mouseleave events rather than mouseover and mouseout.

You can test the behavior quickly with:

$(".myClass").on( {
   'mouseenter':function() { console.log("enter"); },
   'mouseleave':function() { console.log("leave"); }
});

Solution 2:

For simplicity sake, I would just reorganize the html a bit to put the newly displayed content inside the element that the mouseover event is bound to:

<div id="hoverable">
  <a>Hover Me</a>
  <div style="display:none;">
    <input>Test</input>
    <select>
      <option>Option 1</option>
      <option>Option 2</option>
    </select>
  </div>
</div>

Then, you could do something like this:

$('#hoverable').hover( function() { $(this).find("div").show(); },
                       function() { $(this).find("div").hide(); } );

Note: I don’t recommend inline css, but it was done to make the example easier to digest.

Solution 3:

Yeap, guys, use .mouseleave instead of .mouseout:

$('div.sort-selector').mouseleave(function() {
    $(this).hide();
});

Or even use it in combination with live:

$('div.sort-selector').live('mouseleave', function() {
    $(this).hide();
});

Solution 4:

You are looking for the jQuery equivalent of javascript’s prevent event bubbling.

Check this out:

http://docs.jquery.com/Events/jQuery.Event#event.stopPropagation.28.29

Basically you need to catch the event in the children DOM nodes, and there stop their propagation up the DOM tree. Another way, although really not suggested (as it can severely mess with existing events on your page), is to set event capture to a specific element on the page, and it will receive all the events. This is useful for DnD behavior and such, but definitely not for your case.

Solution 5:

I’m simply checking if the mouse-coordinates is outside the element in the mouseout-event.

It works but it’s alot of code for such a simple thing 🙁

function mouseOut(e)
{
    var pos = GetMousePositionInElement(e, element);
    if (pos.x < 0 || pos.x >= element.size.X || pos.y < 0 || pos.y >= element.size.Y)
    {
        RealMouseOut();
    }
    else
    {
         //Hit a child-element
    }
}

Code cut down for readability, won’t work out of the box.

Solution 6:

I agree with Ryan.

Your problem is that the “next” div is not a “child” of A. There’s no way for HTML or jQuery to know that your “a” element is related to the child div in the DOM. Wrapping them and putting a hover on the wrapper means that they are associated.

Please note that his code isn’t in line with best practices, though. Don’t set the hidden style inline on the elements; if the user has CSS but not javascript, the element will hide and will not be able to be shown. Better practice is to put that declaration in the document.ready event.