October DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsWindows FixRecommendedWindows errors stealing your time? Find the fix fastScan stability, cleanup and performance issues.Fix NowOctober DealsAmazon USDeal season is back - check today's better picksAmazon US: current deals, useful picks and tech finds.See Picks×
Skip to content
World desk4 min

How to Assign Events to Every Element With the Same Class

Use querySelectorAll() and forEach() to add events to every matching element, or delegate from a stable ancestor when same-class elements are added dynamically.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use document.querySelectorAll() to collect every current element with a class, then iterate the returned NodeList and call addEventListener() on each element. Read event.currentTarget inside the handler to identify the element whose listener ran.

function handleClick(event) {
  const element = event.currentTarget;
  console.log(element.dataset.id);
}

document.querySelectorAll('.same-class').forEach((element) => {
  element.addEventListener('click', handleClick);
});

Select every matching element

A class selector starts with a period. querySelector() returns only the first matching descendant, while querySelectorAll() returns all current descendants that match the CSS selector. The result is a NodeList, so register the listener for each item rather than calling addEventListener() on the collection itself.

As an Amazon Associate I earn from qualifying purchases.

const buttons = document.querySelectorAll('.save-button');

function save(event) {
  event.currentTarget.classList.add('saved');
}

buttons.forEach((button) => {
  button.addEventListener('click', save);
});

addEventListener() sets up a callback on an individual EventTarget. It has been broadly available across browsers since July 2015.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Identify the element that was clicked

Use currentTarget for direct listeners

With a listener attached directly to each matching element, event.currentTarget is the element running the handler. In a normal function, this also refers to that element, but currentTarget remains predictable when the handler is an arrow function.

document.querySelectorAll('.item').forEach((item) => {
  item.addEventListener('click', (event) => {
    console.log(event.currentTarget.textContent);
  });
});

Use target when you need the original click target

event.target is the deepest element where the event began. If a button contains an icon, the target may be the icon, whereas currentTarget is the button with the listener.

document.querySelectorAll('.action-button').forEach((button) => {
  button.addEventListener('click', (event) => {
    console.log('button:', event.currentTarget);
    console.log('original target:', event.target);
  });
});

Choose direct listeners or event delegation

Approach Best fit How matching works Teardown
Direct listeners Elements already present and independently handled Each element receives its own listener Remove the listener from each element using the same callback reference
Delegation Items added or removed after setup, or a large changing list One stable ancestor receives the event and filters a matching descendant Remove one listener from the ancestor using its callback reference

Direct listeners for existing markup

Direct registration is easy to read and lets the handler use event.currentTarget without additional filtering. It does not automatically cover elements inserted after the query runs.

Delegation for dynamic content

DOM events propagate through ancestors. Attach one listener to a stable container, find the nearest matching descendant, and reject matches outside that container.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
const list = document.querySelector('.list');

function save(button) {
  button.classList.add('saved');
}

list.addEventListener('click', (event) => {
  const button = event.target.closest('.save-button');
  if (!button || !list.contains(button)) return;
  save(button);
});

The containment check matters when nested components could contain another element with the same class. It ensures the handler acts only on a button belonging to this list.

Delegation and nested markup

Because a click on an icon bubbles to the list, closest('.save-button') recovers the intended button even when the original event.target is a child element.

Handle elements created later

The NodeList returned by querySelectorAll() is static. Adding a new matching element later does not add a listener to it.

  • Run the query again after inserting new elements and register the handler on the new results.
  • Attach the listener during the code that creates each element.
  • Delegate from a stable ancestor when the collection changes frequently.
function addSaveButton(id) {
  const button = document.createElement('button');
  button.className = 'save-button';
  button.dataset.id = id;
  button.addEventListener('click', save);
  document.querySelector('.list').append(button);
}

Remove listeners safely

Keep a named handler when a component must be destroyed. removeEventListener() requires the same function object used for registration, together with compatible capture options.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
function handleClick(event) {
  console.log(event.currentTarget.dataset.id);
}

const button = document.querySelector('.save-button');
button.addEventListener('click', handleClick);

// Later, during teardown:
button.removeEventListener('click', handleClick);

An inline function created during removal is a different object and will not unregister the original listener.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Avoid duplicate and unexpected handlers

Prevent duplicate registration

If a rendering function runs repeatedly and attaches listeners each time, one click can invoke the handler multiple times. Centralize setup, mark initialized components, or remove the previous listener before re-registering it.

Inspect propagation

If a parent handler runs unexpectedly, check which elements receive the event and whether code calls stopPropagation() or stopImmediatePropagation(). These methods change how the event continues through the DOM and among listeners.

Check the selector and collection type

  • Use .same-class, including the leading period.
  • Use querySelectorAll() when more than the first match is required.
  • Iterate the returned NodeList before calling addEventListener().
  • Use delegation or a fresh query for elements added after initial setup.

Practical decision guide

  1. Are all matching elements present when setup runs? Use querySelectorAll() and forEach().
  2. Will matching elements be inserted later? Delegate from a container that already exists, or attach the listener as each element is created.
  3. Does the handler need the element with the listener? Read event.currentTarget.
  4. Can a click originate inside nested markup? Use event.target.closest() under delegation.
  5. Will the component be removed or re-rendered? Preserve the handler reference and plan teardown to avoid leaks or duplicate callbacks.

The Bottom Line

For current elements, select the class with querySelectorAll(), iterate the NodeList, and register one listener per element. For changing content, put one listener on a stable ancestor and use closest() plus a containment check to identify the matching descendant.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
PC Slower Than It Used to Be?Free scan - under a minute
Crashes, No Sound, or Screen Glitches?Free driver scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.