Suggest an editImprove this articleRefine the answer for “Difference between event.target and event.currenttarget in JavaScript”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**`event.target`** is the element that fired the event. **`event.currentTarget`** is the element where the handler is attached. ```javascript parent.addEventListener('click', (e) => { // Click on child button: console.log(e.target.id); // "child" console.log(e.currentTarget.id); // "parent" }); ``` **Key:** `target` stays fixed during bubbling; `currentTarget` updates at each handler.Shown above the full answer for quick recall.Answer (EN)Image**`event.target`** is the element that actually fired the event. **`event.currentTarget`** is the element that holds the event handler. ## Theory ### TL;DR - `event.target` is where the event started (the button you clicked inside a div). - `event.currentTarget` is where your `addEventListener` lives (the div itself). - During bubbling, `target` stays fixed; `currentTarget` changes with each handler. - Need to know what was clicked? Use `target`. Need the element with the handler? Use `currentTarget`. - For event delegation on dynamic lists, `target` is what you want. ### Quick example ```html <div id="parent" style="padding: 20px; background: lightblue;"> <button id="child">Click me</button> </div> ``` ```javascript const parent = document.getElementById('parent'); parent.addEventListener('click', (event) => { console.log(event.target.id); // "child" — the button was clicked console.log(event.currentTarget.id); // "parent" — handler lives here }); ``` Click the button: `target` points to the button, `currentTarget` points to the div. The handler is on the div, but the click happened on the button inside it. ### Key difference When an event bubbles up the DOM, `event.target` stays locked to the original element where the event fired. `event.currentTarget` updates at every step and always reflects the element whose handler is currently running. So if you have nested divs with handlers on each, `target` is the same in all of them, but `currentTarget` is different in each one. ### When to use - **Dynamic children (event delegation):** use `target`. Attach one listener to a parent `<ul>` and check `e.target` to find which `<li>` was clicked. Works even for items added after page load. - **Handler's own element:** use `currentTarget`. Toggling a class or reading dimensions of the element that owns the handler. - **More than 10 dynamic children:** delegation with `target` saves attaching individual listeners to each one. - **Single element with a handler:** `currentTarget` is predictable and needs no extra checks. ### Comparison table | | `event.target` | `event.currentTarget` | |---|---|---| | Points to | Element that fired the event | Element with the handler attached | | During bubbling | Fixed (does not change) | Updates at each handler | | Equals `this` in handler? | Not always | Yes (non-arrow functions) | | Use for | Event delegation, detecting source | Operating on the handler's own element | ### How the browser sets these The browser dispatches events following the DOM Level 2/3 spec: capture phase down, target phase, bubble phase up. Each time a handler runs, the engine sets `currentTarget` to the element that registered that specific listener. `target` is set once at dispatch and never changed again. That is why after `stopPropagation()`, `target` is still the original element. ### Common mistakes **Mistake: styling `target` when you mean the handler's element** ```javascript // Handler on div; user clicks a nested img inside the div elem.addEventListener('click', (e) => { e.target.style.background = 'red'; // Paints the img, not the div }); ``` Fix: `e.currentTarget.style.background = 'red'`. **Mistake: toggling a class on `target` without a guard** ```javascript parent.addEventListener('click', (e) => { e.target.classList.toggle('active'); // Toggles on any child: span, p, img... }); ``` Fix: add a check first. `if (e.target.matches('button')) e.currentTarget.classList.toggle('active')`. **Mistake: assuming `target === currentTarget` always** They are only equal when you click directly on the element that holds the handler. The moment a nested child is clicked, they diverge. I have seen this break tooltip close-handlers where clicking a span inside a tooltip wrapper closes the tooltip itself, because the handler checked `e.target` instead of `e.currentTarget`. ### Real-world usage - **React:** `SyntheticEvent.target` for form delegation (reading `e.target.value` in a shared `onChange`). `currentTarget` for accessing the form element itself. - **Vue:** `$event.target` inside `v-on` for dynamic slot content. - **Vanilla delegation:** one listener on a table, `e.target.closest('tr')` to get the clicked row. - **jQuery migration:** `$(event.target).closest()` patterns map directly to `e.target.closest()` in vanilla. ### Follow-up questions **Q:** What happens to `target` and `currentTarget` in the capture phase? **A:** Both are set during capture too. `currentTarget` matches the capturing element; `target` is still the original dispatcher. **Q:** Does `stopPropagation()` change `target`? **A:** No. `target` is fixed at dispatch. `stopPropagation()` only stops the event from moving to the next element in the chain. **Q:** In a non-arrow handler function, what does `this` equal? **A:** `this` equals `currentTarget`. That is why older code used `this` instead of `event.currentTarget`. Arrow functions break this because they do not bind their own `this`. **Q:** What if the clicked element is the same as the handler's element? **A:** Then `target === currentTarget`. This happens when you click directly on the element you attached the listener to, with no child elements in between. **Q:** In React Portals, where does `target` point? **A:** `target` points to the portal child. Even though the Portal renders outside the parent DOM tree, React's synthetic event system re-dispatches through the React component tree, so delegation still works across the portal boundary. ## Examples ### Event delegation on a dynamic list ```javascript const list = document.getElementById('list'); // One listener handles all items, including ones added later list.addEventListener('click', (e) => { if (e.target.tagName === 'LI') { console.log('Clicked:', e.target.textContent); e.target.classList.toggle('selected'); } // e.currentTarget is always the #list element }); // This new item works immediately — no extra listener needed const newItem = document.createElement('li'); newItem.textContent = 'New item'; list.appendChild(newItem); ``` One handler on the parent covers all items, current and future. `e.target` tells you which specific item was clicked; `e.currentTarget` stays locked to the list. ### Form with a shared handler using both properties ```javascript const form = document.getElementById('signup-form'); form.addEventListener('change', (e) => { const field = e.target; // Which input changed const formEl = e.currentTarget; // The form element itself console.log('Field name:', field.name); console.log('New value:', field.value); // Re-validate the whole form using the form element const allInputs = formEl.querySelectorAll('input'); const allFilled = [...allInputs].every(i => i.value.trim() !== ''); formEl.querySelector('#submit').disabled = !allFilled; }); ``` `e.target` identifies which field changed. `e.currentTarget` gives access to the whole form for re-validation. Both properties doing different jobs inside the same handler.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.