• Bursting the Event Bubble

    Feb 15 2006

    Have you ever wanted to prevent a JavaScript event from firing when it has been bubbled up from a child element? For example, let's say you have an onMouseOver event for a parent element. Anytime the mouse moves over any of the children elements, the parent's onMouseOver event will keep firing. Or, let's say you have an onMouseDown event on a parent and another on its child. Both onMouseDown events will fire when someone clicks the child. Sometimes this can be a real pain.

    Anyway, enough examples, let's look at a way to avoid this. We need a way to fire an event only when the element with the event handler is the target element of the event. Here's the solution event handler:

    function eventHandler(e) {
         e = e || window.event;
         var target = e.srcElement || e.target;
         if (target != this) return;
         
         // the rest of the function
    }

    Simple enough, once we have the code. Let's look at what it does.

    First, we find the event object. In Firefox and Safari, it's a parameter to the function. In Internet Explorer, it's in window.event.

    Having that, we need to find the target in the event object. This is the first element the event fires on, the inner-most or top-most element. In Safari and Firefox, it's target, but in Internet Explorer it's srcElement.

    Finally, we will compare against the element the event is attached to. The element the event handler is attached to can be accessed easily with the this variable.

    For more information on event handlers, I highly recommend the excellent resources at QuirksMode:

    Update: you need to do a little bit more if you are dealing with mouseout events. If you move the mouse into a child, this triggers the mouseout event on the parent. In this case, the target will match the parent. So, you'll also have to get the 'related' element (the child) and make sure the target isn't one of the ancestors. Here is the updated function for mouseout events:

    function mouseOutEventHandler(e) {
         e = e || window.event;
         var target = e.srcElement || e.target;
         if (target != this) return;
    
         var related = e.relatedTarget || e.toElement;
         while (related != this && related.nodeName != 'BODY')
              related = related.parentNode;
         if (related == this) return;
       
         // the rest of the function
    }

    Special thanks to QuirksMode's Mouse Events page for helping me figure out that one!

  • Comments

    1. Steven Stoft at 3:44am on January 29, 2007

    I'm currently using onmouseover(param1, p2) inside a div tag, but I would like to use your code to solve the bubbling problem.
    However I cannot see how to pass my parameter to your mouseOutEventHandler(e) so that the "rest of function" can do what I need.

    Nice web site. Thanks.
    Steve

    2. Diego at 3:51am on November 8, 2007

    I can't seem to burst the event bubble, I've spent countless hours on my specific scenario without avail. Please help.

    I tried the code above but I get a strange result. The code below 'the rest of the function' only fires when the mouse leaves the right side of the div.

    I have a div with other elements in it, I need to fire the mouseover/mouseout events only when I leave the whole div that contains everything else.


    Regards,


    Diego

    3. Llewellyn at 3:47am on January 28, 2008

    Here's another easy way to stop the event from bubbling from the event handler:

    function doSomething(e)
    {
    if (!e) var e = window.event;
    e.cancelBubble = true;
    if (e.stopPropagation) e.stopPropagation();
    }

    4. veer at 1:40am on March 7, 2009

    i want to know what is 'e' in all the above function, ex. function mouseOutEventHandler(e) , how did we get 'e' for firefox means what we have to pass when calling the function

    5. Stephen at 12:51pm on September 16, 2009

    Yeah I do wish someone would answer the question about what we're supposed to pass into mouseOutEventHandler(e).

    Why isn't that explained in this otherwise nice blog entry. I mean, is it supposed to be obvious?

    6. Jesse Skinner at 1:08pm on September 16, 2009

    @veer, @Stephen - This is an event handler function, so you would assign it to the mouseout event of some element. That might look like this:

    var element = document.getElementById('my_element');
    element.onmouseout = mouseOutEventHandler;

    Then the 'e' will be the event object that is passed to every event handler (except in IE, where the event object is found at window.event, which is what the first line of the function is for).

    7. Stephen at 12:07pm on September 17, 2009

    That's awesome response time and response contents! Thanks. It works.

    I was trying to use the onmouseout attribute of the div tag itself to call the javascript function. I wish it was that easy.

    Ruby on Rails is bringing lots of noobs like me into the complex world of web application development

    Commenting is now closed. Come find me on Twitter.