What is the difference between preventDefault and stopPropagation?
They control two completely separate things. PreventDefault stops the browser's default action for the event, such as following a link, submitting a form or scrolling into view. StopPropagation stops the event travelling any further through the tree, so the listeners on the ancestors never see it.
// A tiny stand-in for the DOM that models a cancelable default action.
const link = {
tagName: "A",
listeners: {},
defaultPrevented: false,
addEventListener(type, handler) { (this.listeners[type] ||= []).push(handler); },
dispatchEvent(event) {
const payload = {
...event,
preventDefault() { this.defaultPrevented = true; },
stopPropagation() { this.propagationStopped = true; },
};
for (const handler of this.listeners[event.type] ?? []) {
handler(payload);
if (payload.cancelable && payload.defaultPrevented) {
console.log("default action cancelled");
return;
}
}
console.log("default action ran");
},
};
link.addEventListener("click", (event) => {
event.preventDefault(); // stop the browser following the link
event.stopPropagation(); // stop the event going further up
console.log("handled");
});
link.dispatchEvent({ type: "click", cancelable: true, defaultPrevented: false });There is a third method that completes the picture. The stopImmediatePropagation method stops the event travelling and also prevents any other listener on the same element from running. PreventDefault and stopPropagation both act on the current event, and neither of them stops other listeners on the same element from being called.
One detail that matters in practice. PreventDefault only works if the event is cancelable, and not every event is. The click event on a link is cancelable, but the load event on an image is not, so calling preventDefault on it does nothing. The cancelable property on the event tells you which you have.
Another detail: preventDefault is respected by the browser only for the default action of that event. It has no effect on what your own code does, so if your handler already ran and did something, that still happened.