How JavaScript Event Delegation Works

By on  

One of the hot methodologies in the JavaScript world is event delegation, and for good reason.  Event delegation allows you to avoid adding event listeners to specific nodes;  instead, the event listener is added to one parent.  That event listener analyzes bubbled events to find a match on child elements.  The base concept is fairly simple but many people don't understand just how event delegation works.  Let me explain the how event delegation works and provide pure JavaScript example of basic event delegation.

Let's say that we have a parent UL element with several child elements:

<ul id="parent-list">
	<li id="post-1">Item 1</li>
	<li id="post-2">Item 2</li>
	<li id="post-3">Item 3</li>
	<li id="post-4">Item 4</li>
	<li id="post-5">Item 5</li>
	<li id="post-6">Item 6</li>

Let's also say that something needs to happen when each child element is clicked.  You could add a separate event listener to each individual LI element, but what if LI elements are frequently added and removed from the list?  Adding and removing event listeners would be a nightmare, especially if addition and removal code is in different places within your app.  The better solution is to add an event listener to the parent UL element.  But if you add the event listener to the parent, how will you know which element was clicked?

Simple:  when the event bubbles up to the UL element, you check the event object's target property to gain a reference to the actual clicked node.  Here's a very basic JavaScript snippet which illustrates event delegation:

// Get the element, add a click listener...
document.getElementById("parent-list").addEventListener("click", function(e) {
	// e.target is the clicked element!
	// If it was a list item
	if(e.target && e.target.nodeName == "LI") {
		// List item found!  Output the ID!
		console.log("List item ", e.target.id.replace("post-"), " was clicked!");

Start by adding a click event listener to the parent element.  When the event listener is triggered, check the event element to ensure it's the type of element to react to.  If it is an LI element, boom:  we have what we need!  If it's not an element that we want, the event can be ignored.  This example is pretty simple -- UL and LI is a straight-forward comparison.  Let's try something more difficult.  Let's have a parent DIV with many children but all we care about is an A tag with the classA CSS class:

// Get the parent DIV, add click listener...
document.getElementById("myDiv").addEventListener("click",function(e) {
	// e.target was the clicked element
	if(e.target && e.target.nodeName == "A") {
		// Get the CSS classes
		var classes = e.target.className.split(" ");
		// Search for the CSS class!
		if(classes) {
			// For every CSS class the element has...
			for(var x = 0; x < classes.length; x++) {
				// If it has the CSS class we want...
				if(classes[x] == "classA") {
					// Bingo!
					console.log("Anchor element clicked!");
					// Now do something here....

The example above requires not only a tag match but also a CSS class match.  While this is a bit more complex, it's still fairly simple in the grand scheme of things.  For example, if the A element had a SPAN tag in it, the SPAN tag would be the target element.  In that case, we'd need to walk up the DOM tree to find out if it contained an A.classA element we were looking for.

Since most developers use a JavaScript library for their DOM element and event handling, I recommend using the library's method of event delegation, as they are capable of advanced delegation and element identification.

Hopefully this helps you visually the concept behind event delegation and convinces you of delegation's power!

Track.js Error Reporting

Recent Features

  • Facebook Open Graph META Tags

    It's no secret that Facebook has become a major traffic driver for all types of websites.  Nowadays even large corporations steer consumers toward their Facebook pages instead of the corporate websites directly.  And of course there are Facebook "Like" and "Recommend" widgets on every website.  One...

  • Camera and Video Control with HTML5

    Client-side APIs on mobile and desktop devices are quickly providing the same APIs.  Of course our mobile devices got access to some of these APIs first, but those APIs are slowly making their way to the desktop.  One of those APIs is the getUserMedia API,...

Incredible Demos

  • MooTools&#8217; AutoCompleter Plugin

    One of the famous MooTools plugins is Harald Kirschner's AutoCompleter plugin. AutoCompleter takes a term input by the user and searches for matches -- an obviously help to the user. Here's how to make the most of Harald's great plugin. The XHTML All we...

  • CSS Counters

    Counters.  They were a staple of the Geocities / early web scene that many of us "older" developers grew up with;  a feature then, the butt of web jokes now.  CSS has implemented its own type of counter, one more sane and straight-forward than the ole...


  1. Good overview. I was just wondering could use:

    e.target.className.split(" ").indexOf(class) !=-1

    Instead of the loop. I know it is not supported everywhere but everyone with addEventListener supports indexOf

    • Daniel

      The availability of Array.indexOf is independent of any one method or nodeList, it is dependent on the browser you are using and the version of JavaScript it implements. Firefox has had indexOf for some time now, so to with later version of Google Chrome.

    • Art Taylor

      While indexOf isnt supported by some older browsers, a polyfill can be found at: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf

    • Hott Dogg

      I think it will be even better to use RegExp for class testing :)
      var re = new RegExp('\\b'+class+'\\b');

    • Yep, that would certainly work well too!

    • Alexey

      Why not element.classList.contains(className)?

  2. Nice post, the importance of event delegation can’t be hyped enough!

  3. Blaine

    Good concept. When dealing with dynamic content that needed events, I typically loaded with a “rel” set to “untouched”, or without one at all and load a function that would look for all untouched methods or without the “touched” rel, give them the correct event, and set their rel’s to “touched”.

    Is there a performance improvement done by using your method?

    • Depends on what you’re doing. It occurs to me, however, that you may need to run the event routine multiple times if you ever add elements dynamically. The rel tag solution, if you only want to do something once, isn’t a bad idea. Elitists would tell you to use data-[whateverAttributeName].

  4. santhanam

    Good Example. Is there is any thing for Memoization.?

  5. Patrick Hayes

    var classes = e.target.className.split(" ");
    // Search for the CSS class!
    if(classes) {

    When className returns an empty string, split should return an array containing one empty string, which evaluates to true in an if statement. Otherwise split will return the split elements or an array with the original string. That being said, is “if (classes)” cautionary, is it directed at a known browser, is it unnecessary, or am I missing a case where the if would be false? I can’t blame one for being cautious especially with browser reputation being what it is and can’t rule out that I’m missing something!

  6. Ralph

    I’m an experienced programmer, but relatively new to javascript, but not new to GUI programming (Windows, Swing, Android, etc.).

    I read a lot about the importance of event delegation, but I’m skeptical. To me, it seems like it’s a venerated “best practice” that’s no longer relevant. I just can’t believe that modern computers and browsers are affected by the very marginal gains (?) offered by event delegation. What exactly *are* the benefits?

    From a coding style perspective, event delegation shows odd cohesion.When coding event handling in other environments (like desktop, etc.) one normally doesn’t have a central event handler with an embedded case structure to test what was clicked. Especially with the common handler tied to some UI implementation which could very well change as users ask for changes to the UI. User: “Please move that button on the toolbar.” Of course, event handlers on the individual items would mean such changes are not problematic.

    The author says “what if LI elements are frequently added and removed from the list? Adding and removing event listeners would be a nightmare.” Ok, for *semantically* grouped items, like items in a list, I can see it (just like you’d have a single event handler for a combo box, and not on the items in the box).

    So… Is this some venerated yet anachronistic style, or are there any statistics or tests I can run that show the benefits.

    • Chris Baker

      There are indeed direct benefits. In standard application programming, one may deal more directly with the garbage collector or at least have a better conception of how the GC operates. In web development, the GC is completely variable per user agent — you have literally no idea how or when it will operate because each user may potentially use a different agent.

      Imagine a use case where you have a grid of several hundred dynamically generated table cells (think an hour-by-hour availability calendar): attaching an event to each of these cells would, for starters, take a moment. While you’re looping over them, the browser UI thread is locked and the user perceives bad performance. You also wind up with several hundred listeners, and depending on your script architecture that could also mean several hundred function references. This is in itself weighty… but now the user switches dates and you have a new batch of cells injected into the table. Do you loop the old cells and remove the listener from each? That will take time, then you have to loop again to apply the new listeners. Do you just ignore the old and only worry about the new? Now you have several hundred references sitting in memory, waiting for the mythical GC that will fire who-knows-when. Plus, you may have created circular references and those listeners will never leave memory, *even when the user navigates to a completely different page*. Your function references are still sitting in memory, too. That is one quite feasible use-case where a single event listener and delegation eliminates all those references and concerns.

      In your toolbar button example, the delegating event would be attached to the toolbar itself. This pattern actually compliments a more flexible UI; you don’t think about the event, you just move the button. Or add a new one. Or delete one. No matter what change takes place, the single event listener will bubble up any actions.

      I don’t think the cohesion is odd at all — one would use delegate events to apply an action to a specific group of elements. Cohesion already existed; these buttons are toolbar buttons, and when you click on, a centralized handler will determine what happens. This is how you already code (presumably), the real differences is that without delegation, you have more references to keep track of.

      Delegation makes most sense when it is used with mutually cohesive elements: LIs in a UL, TRs in a TABLE, etc. Control icons and the like are also another common use, though they aren’t semantically grouped they still have an underlying cohesion whether you used delegation or not.

  7. Carlos

    hi, i try create a function same live, delegate, on of jquery, any idea?

  8. Anup

    Thanks for explaining this in very simple manner. Now I can take benefit of it in jquery OR all js libraries as well.
    No need treat it as like magic.

  9. Just for the record…

    In jQuery you can implement it using CSS selectors like this:

    jQuery("#myDiv a.classA").bind("click", function(e) {
        var clickedElement_jQuery = $(e.currentTarget); // gets the jQuery object for the "current target" element, i.e. the clicked element
        var clickedElement_DOM = clickedElement_jQuery.get();
        // Do something...
    • It’s actually even easier than that! Using jQuery’s on the value of this in the callback is bound to the target element. So:

      jQuery("#myDiv").on("click", "a.classA", function() {
         var targetElement = $(this);
    • krishna

      this is not event delegation method this is direct method

      Event Delegation:

      $("#myDiv").on("click", "a.classA", function(e){
  10. This article is a very good example of event handle in JS. But it would be better if the author can talk more about the cross browser issue.

  11. pradeep

    Good article but
    i prefer to bind all events in custom event binder.
    just give a JSON to event binder and boom.

    • rexs

      Can you elaborate more on your custom event binder?
      What is its benefits over the event delegation mentioned in this article?

  12. Hassan

    The target.nodeName check fails if there’s an span tag inside the A element, so the nodeName returns “SPAN” and not “A”. Is there an easy way to get around this?

  13. Hey – thanks a lot for this post! This solution will tidy up my implementation nicely.

  14. Alex

    Good explanation, it makes things clear

  15. I liked the post… I used it as inspiration for my own article :)

  16. natee

    I think the className should handle like this:

    var classes = e.target.className.replace(/\s+/g," ");

    for when there is more than one space in attribute class

  17. I’m just wondering why you are checking if e.target exists, in which cases it wouldn’t?

  18. YiJu

    So, if you add blur or focus events on input.

    How to delegate its events for refresh new DOM events??

Wrap your code in <pre class="{language}"></pre> tags, link to a GitHub gist, JSFiddle fiddle, or CodePen pen to embed!

Recently on David Walsh Blog

  • OSCON Portland:  Conference  Discount!

    O'Reilly puts on the best web industry conferences in the world.  These conferences include Fluent Conference, Velocity Conference, and the upcoming OSCON in Portland, Oregon from July 20-24.  Open Source Convention (OSCON) is a conference that focuses specifically on open source developers and the tools and possibilities...

  • Follow Redirects with cURL

    I love playing around with cURL. There's something about loading websites via command line that makes me feel like some type of smug hacker, just like tweeting from command line does. I recently cURL'd the Google homepage and saw the following: I found it weird that Google...

  • Developers Have WordPress, Amateurs Have Squarespace, Professional Designers Have the NEW Webydo!

    Web design platforms have traditionally come in one of two varieties. There are the solutions like WordPress and Drupal that are incredibly powerful, but an understanding of web development and coding is required to be able to use those platforms effectively. On the other side of the...

  • Chris Coyierâs Favorite CodePen Demos II

    Hey everyone! Before we get started, I just want to say it’s damn hard to pick this few favorites on CodePen. Not because, as a co-founder of CodePen, I feel like a dad picking which kid he likes best (RUDE). But because there is just so...

  • GSAP + SVG For Power Users: Motion Along A Path

    Now that the GreenSock API is picking up steam, there are many tutorials and Getting Started guides out there to provide good introductions to the library, not to mention GreenSock’s own Forum and Documentation. This article isn’t intended for beginners, but rather a...