What is the event propagation path in the browser?
Every DOM event travels through three phases. The capture phase starts at the root of the tree and works down towards the target. The target phase is the event at the element the user actually interacted with. The bubble phase then works back up from the target to the root.
A listener registered without options runs during the bubble phase, which is why a click handler on a list item still fires when you click a child element inside it. A listener registered with the capture option set to true runs during the capture phase, which fires first, before the event reaches the target.
// The DOM only exists in a browser, so check before using it.
if (typeof document !== "undefined") {
const outer = document.querySelector("#outer");
const inner = document.querySelector("#inner");
outer.addEventListener("click", (event) => {
console.log("outer saw a click on", event.target.id);
});
inner.addEventListener("click", (event) => {
console.log("inner saw a click on", event.target.id);
console.log("current target is", event.currentTarget.id);
});
inner.click();
} else {
console.log("No DOM in this runtime - open a browser console to try it.");
}The two properties on the event object are worth being able to name. The target property is the deepest element the event happened on, so a click on the text inside a button reports the text node's parent as the target rather than the button. The currentTarget property is the element whose listener is currently running, which is the one that changes as the event travels. Confusing the two is the source of a lot of confusing bug reports, so it is worth stating the difference clearly in an interview.
Some events do not bubble. The focus and blur events bubble, but the focusin and focusout events were added as bubbling versions of them. The mouseenter and mouseleave events also do not bubble, which is why mouseover and mouseout are often used instead when you need delegation.