This method will not be possible if a similar listener has been added to document
before your code has had a chance to run, and that listener calls stopImmediatePropagation
, but luckily, such things are quite rare.
All you need to do is add a click listener to document
in the capturing phase, so that your listener runs as soon as it possibly can (it will run before any bubbling listeners fire, and will run before any capturing listeners, except capturing listeners on document
):
document.addEventListener(
'click',
() => {
console.log('global click detected');
},
true // <-- very important: trigger listener in capturing phase
);
document.querySelector('#foo').addEventListener('click', (e) => {
e.stopPropagation();
console.log('foo clicked, stopPropagation called');
});
<div id="foo">click</div>
Example snippet where the "global click detected" wouldn't work, due to a capturing listener on document
that calls stopImmediatePropagation
:
document.addEventListener(
'click',
(e) => {
e.stopImmediatePropagation();
e.stopPropagation();
},
true
);
// cannot intercept click now, due to stopImmediatePropagation
document.addEventListener(
'click',
() => {
console.log('global click detected');
},
true
);
<div id="foo">click</div>
Note that adding listeners in the capturing phase cannot be done with jQuery - have to use standard Javascript for that.
This sort of technique is very handy for intercepting events when you can't control other code on the page.