JavaScript: Event Delegation

By Xah Lee. Date: . Last updated: .

What is Event Delegation?

Suppose we want to color all paragraph “p” items red when user clicks it.

for (let ele of document.querySelectorAll ("p")) {
ele.addEventListener ( "click", ((evt) => { evt.target.style.color="red"; }) , false);
} 

[see for-of Loop]

instead of attaching a event handler to “p”, we can attach it a parent element, such as “body”. Because when mouse hovers over any “p”, it is also hovering over “body”.

for (let ele of document.querySelectorAll ("body")) {
ele.addEventListener ( "click", ((evt) => { if ( evt.target.nodeName === "P" ) { evt.target.style.color="red"; } }) , false);
}

Try it. Copy and paste the above code into your browser's JavaScript console. Then, click on any paragraph.

(note: in real code, you shouldn't use “body” as parent, since clicking anywhere is body. Use a parent closest to the elements you want.)

Why use Event Delegation?

If you use event delegation, you can add child elements without needing to attach event to them. This makes your implementation simpler. (in complex web app, you may be constantly adding and removing elements dynamically.)

Also, relegation may save you memory, since you have just one listener instead of potentially hundreds. (for a example of this scenario, see Unicode Search 😄)

How Event Delegation Works?

Delegation works fundamentally because visible (non-hidden) nested elements.

When element “p” is inside a “div”, and when user clicks on “p”, the click is also on “div” because “div” encloses “p”. So, which should fire first?

dom eventflow
DOM event flow http://www.w3.org/TR/DOM-Level-3-Events/#dom-event-architecture

DOM defines 3 phase for event dispatch. Quote:

What that basically means is that, when a event (such as mouse click) applies to all nested elements, the order of event firing is from outer element to inner element then back to outer element.

Suppose you attach a mouseover event handler to <ul>.

When user mouse hovers over <li>, your event handler will run because mouse is also hovering over <ul>. The browser will go thru a event propagation path, which will start at <ul> then go to its nested elements until it hits the element that the mouse is on, then travel back to the <ul> element.

For each element in the event propagation path, it'll set eventObject.target to that element. So, your event handler can check if element's tag is <li>.

BUY ΣJS JavaScript in Depth