Event capture explained

By Hallvord R. M. Steen

Occasionally I have been grumbling about un-intended event capture. Here is a more detailed explanation of the feature and the issues.

What is event capture?

If you call addEventListener with true as the third argument you create a capturing event. The difference from a normal event is that the capturing listener detects all events in the document before they are sent to the actual target of the event. So, for example if you have

  <body>
    <p onclick="alert('you clicked the p')">click to test</p>

and do
document.body.addEventListener('click', func, true)
the event listener on BODY will run before the onclick on the P tag. The event listener on BODY can choose to stop propagation so that the event will not actually be passed on to the P tag. For example,
document.body.addEventListener( 'click', function(e){ if(confirm('Stop event?'))e.stopPropagation(); }, true );

If the BODY event listener was not a capturing one, the P onclick would trigger first, then the BODY's listener would fire. So event capture is simply a way to change the order different elements will "see" the event.

Implementations

addEventListener and capturing events is part of the DOM2 Events standard, which is supported by Opera, Gecko/Firefox, and Safari. IE supports the slightly different attachEvent API.

Implementation differences

Capture on target

The DOM spec states that capturing events should not fire on target, because the idea of a capturing event is to detect events before they reach their targets. Because of bugs in Gecko and Safari, web content that is tested mostly with Firefox or other Gecko-based browsers sometimes expects capturing listeners to fire on target. Such content will fail in Opera 7, 8 and current releases of 9 because of its correct implementation of the standard.

Capturing load events

document.addEventListener('load', func, true)
creates a capturing load event listener. Opera supports capture of load events. All items (images, style sheets, external scripts) loaded into a document has their own load event, and if you capture load events for the entire document your script is going to run for every such event.
Content that is tested with Gecko or older Safari versions tend to expect only one load event because these browsers do not support load event capture. Such content may fail in Opera because a script that expects to be run only once (for example to initialise the page) may be run hundreds of times.

Removing event listener from event handler

If you have several event listeners for the same event, and one of them removes another one the second will still be called in Opera for that event. This is a known bug but it's limited to very rare use cases.

Advisory

As browsers improve their DOM specification compatibility, a script that uses event capture without intending to do so will become incompatible with more and more browser versions. As a web developer, you can avoid the implementation gotchas in browsers and achieve cross-browser compatibility simply by avoiding capturing event listeners unless you know what you are doing. Make sure the third argument of your addEventListener calls defaults to false, not true.

Re-published from http://my.opera.com/hallvors/blog/2006/10/12/2006-10-12-event-capture-explained with minor updates and changes

This article is licensed under a Creative Commons Attribution, Non Commercial - Share Alike 2.5 license.

Comments

The forum archive of this article is still available on My Opera.

No new comments accepted.