Event listeners are called in the order of their registration:
button.addEventListener('click', () => console.log("I run first"))
button.addEventListener('click', () => console.log("I run second"))
Sometimes you want a listener to always run first (or last), but have no control over the order in which other listeners are registered. There is no clean mechanism in the DOM API for this. This card shows some hacks to do it anyway.
Exploiting the capturing phase
Before an event bubbles up from an element to the document, it travels down from the document to the element. This is called the capturing phase.
You can have a listener call in the capture phase by passing an { capture: true } option. Since other code rarely uses capturing, this effectively causes your listener to run before existing listeners:
button.addEventListener('click', () => console.log("I run second"))
button.addEventListener('click', () => console.log("I run first"), { capture: true })
Binding to an ancestor
Listeners bound to an ancestor will still observe a (bubbling) event from its descendants. Since the event bubbles up from its target to the document, you can use a delegating listener to run after most existing listeners:
document.addEventListener('click', ({ target }) => {
if (button.contains(target)) console.log("I run second")
})
button.addEventListener('click', () => console.log("I run first"))
Be mindful of memory leaks when registering listeners that way. In the example above, the listener registered to document will not be garbage collected when button is removed. You need to explicitly remove the listener when the button is detached.
Using a different but related event
In many cases you can find a different event that fires directly before or after the event you're interested in:
input.addEventListener('focus', () => console.log("I run second"))
input.addEventListener('focusin', () => console.log("I run first"))
Avoid event pairs that only go together some of the time. E.g. mousedown fires before click, but mousedown does not fire for keyboard users.