Everything about Event Handlers and Event Propagation

Sep 03, 2022

This has been written over a hundred times before and probably holds more than a hundred answers on StackOverflow. But over time, going through different articles and answers, I curated the important parts and wrote them down in this post.

Event Handling

There are 3 ways to attach a handler to an event in JavaScript.

  • HTML Attribute
  • DOM Property
  • addEventListener()

HTML attribute

This is the old-school way of attaching a handler to an event by adding an attribute to the DOM element.

Remember, a node can only have one onclick attribute. So with this approach, only one handler can be registered for an event.

<div id="el" onclick="kaboom()"></div>

DOM property

This is the JavaScripty way of creating a DOM node on the fly, adding an attribute to it and attaching a handler to the attribute. Since this is almost the same as the previous approach, only one handler can be registered to an event.

<script>
  el = document.querySelector("#el")
  el.onclick = clickMe();
</script>

addEventListener() 🔥

This is the modern way of binding handlers to the event. We can bind any number of handlers with the event and all these handlers will be invoked when that event happens.

<script>
  el.addEventListener("click", (e) => {
	// Some code here that goes KABOOM!
  });
</script>

Event Behaviours

  • preventDefault()
  • Event Bubbling
  • Event Capturing

preventDefault()

There are a handful or pre-defined events that have default actions associated with them. For example,

  • a link by default takes you to the link’s target.
  • if you press the down arrow, the page scrolls down.

In these cases, the custom handlers associated with these elements will get invoked before the default actions are followed by the default actions. If you want to completely unbind this default behavior from the element, you can call the event.preventDefault() in your handler.

Note: This has got nothing to stop the event from bubbling up the DOM.

Event Bubbling & Event Capturing

Events in DOM usually get propagated as a stack of events nested in the web browser.

Event Bubbling

Event bubbling can be better explained with an example.

Let's take a nested DOM structure like this

<div id="parent">
  <div id="child"></div>
</div>

If there are handlers attached to both #parent and #child divs,

  • when the child is clicked, due to the bubbling nature of events, first the handler for the #child div is invoked and then the event propagates to #parent div and its handler will be invoked.

In short, the child first and the parent next as events bubble from the bottom to top.

Event Capturing

Event capturing is more of capturing the event in the DOM and handing it over to event handlers for execution. Events are captured from the top-down, meaning the outermost element is captured first and propagated to the inner elements. Once the events are captured, the bubbling of events starts from the innermost elements.

stopPropagation()

You can stop the bubbling of events from child to parent by calling event.stopPropagation() in the child event handler.

function childHandler(event) {
  event.stopPropagation();
}

Removing an event listener

You can remove an event listener from an element by invoking removeEventListener() on the event, which accepts the event name and handler name as arguments.

function handleClick(e) {
  // go KABOOM!
}

element.addEventListener("click", handleClick);
element.removeEventListener("click", handleClick);

Note: Do not use the anonymous handler method. You should define the function outside the callback and then reference it in back in the removeEventListener callback.

// this is wrong as you cannot remove this event listener
element.addEventListener("click", () => { /* go KABOOM! */ });

That's it, folks. Pl drop a comment if you think this post could be improved in any way.