How to add the same event listener to multiple elements in JavaScript

An event listener is a function that runs when a certain event occurs, such as a click, a keypress, or a mouseover. You can use the addEventListener() method to attach an event listener to a single element, such as a button or a link.

But what if you want to add the same event listener to multiple elements, such as a group of buttons or links? There are two main ways to do this:

  • Query all elements and attach event listener to each of of them.
  • Take advantage of event bubbling by attaching a event listener to common parent element.

Both methods have their advantages and disadvantages. The first method is more straightforward and intuitive, but it requires more code and memory. The second method is more efficient and flexible, but it requires more logic and careful handling of edge cases.

Using querySelectorAll

The first way is to use the querySelectorAll() method to select all the elements that match a certain selector, such as a class name or an attribute. This method returns a NodeList object, which is similar to an array of elements.

You can then use the forEach() method to loop through each element and add the event listener to it.

For example, if you have three buttons with the class name btn, you can add a click event listener to all of them like this:

// select all the buttons with the class name "btn"
const buttons = document.querySelectorAll(".btn");

// loop through each button and add a click event listener
buttons.forEach(function(button) {
  button.addEventListener("click", function() {
    // do something when the button is clicked
    console.log("You clicked a button");
  });
});

Using event delegation

The second way is to use event delegation, which is a technique that takes advantage of event bubbling. Event bubbling is the natural behavior of how events propagate up the DOM hierarchy from the target element that triggered the event to its parent elements and further up to the root of the document.

You can use this feature to add an event listener to a common parent element of the target elements, such as the document or the body. Then, inside the event listener function, you can use the event.target property to check which element triggered the event and perform some logic based on that.

For example, if you have three links with different IDs, you can add a click event listener to the document and check which link was clicked like this:

// add a click event listener to the document
document.addEventListener("click", function(event) {
  // check which link was clicked using the event.target.id property
  switch (event.target.id) {
    case "link1":
      // do something when link1 is clicked
      console.log("You clicked link1");
      break;
    case "link2":
      // do something when link2 is clicked
      console.log("You clicked link2");
      break;
    case "link3":
      // do something when link3 is clicked
      console.log("You clicked link3");
      break;
    default:
      // do nothing if none of the links were clicked
      break;
  }
});

Event bubbling can be convenient when you want to handle events on multiple levels of a DOM structure. However, in some cases, you might want to stop the event from bubbling further up the hierarchy. This can be done using the event.stopPropagation() method within an event handler. For instance:

document.getElementById("child").addEventListener("click", function (event) {
  console.log("Child clicked");
  event.stopPropagation(); // Stop the event from bubbling up
});

In this case, if you click the button, only “Child clicked” will be logged, and the event won’t propagate to the parent element’s event handler.

Event delegation is particularly useful when dealing with dynamic or generated content, where you might not know in advance how many elements will need event handlers or when they will be created. Instead of attaching event listeners to each individual element as it’s created, you attach a single listener to a higher-level container that will always be present.

You should minimize the use of global event listeners on the document or window objects. Attach event listeners to specific elements or containers whenever possible to improve performance and reduce unintended side effects.

Remember to remove event listeners when they’re no longer needed, especially when dealing with long-lived applications or single-page apps. Failing to remove unused event listeners can lead to memory leaks.