The Difference Between jQuery’s .bind(), .live(), and .delegate()

The difference between .bind(), .live(), and .delegate() is not always apparent. Having a clear understanding of all the differences, though, will help us write more concise code and prevent bugs from popping up in our interactive applications.

The jQuery team have announced in v1.7 a new method for binding events called on. This method combines the functionality of live, bind, and delegate described below, allowing you to specify the binding method based the arguments passed rather than by using different function names.

The basics

The DOM tree

First, it helps to visualize the DOM tree of an HTML document. A simple HTML page would look like this:

HTML DOM Structure

Event bubbling (aka event propagation)

When we click a link, it fires the click event on the link element, which triggers any functions we bound to that element’s click event.

$('a').bind('click', function() { alert("That tickles!") });

So a click will trigger the alert.

HTML DOM Structure

That click event then propagates up the tree, broadcasting to the parent element and then to each ancestor element that the click event was triggered on one of the descendent elements.

HTML DOM Structure

In the context of manipulating the DOM, document is the root node.

Now we can more easily illustrate the difference between .bind(), .live(), and .delegate().

.bind()

$('a').bind('click', function() { alert("That tickles!") });

This is the most straight forward binding method. jQuery scans the document for all $('a') elements and binds the alert function to each of their click events.

.live()

$('a').live('click', function() { alert("That tickles!") });

jQuery binds the alert function to the $(document) element, along with 'click' and 'a' as parameters. Any time an event bubbles up to the document node, it checks to see if the event was a click and if the target element of that event matches the 'a' CSS selector. If both are true, the function executes.

The live method can also be bound to a specific element (or “context”) other than document, like this:

$('a', $('#container')[0]).live(...);

.delegate()

$('#container').delegate('a', 'click', function() { alert("That tickles!") });

jQuery scans the document for $('#container'), and binds the alert function along with the click event and 'a' CSS selector as parameters. Any time an event bubbles up to $('#container'), it checks to see if the event was a click and if the target element of that event matches the CSS selector. If both checks are true, it executes the function.

Notice this is similar to .live(), except that it binds the handler to the specified element instead of the document root. The astute JS’er might conclude that $('a').live() == $(document).delegate('a'), right? Well, no, not exactly.

Why .delegate() is better than .live()

jQuery’s delegate method is generally preferred to the live method for a few reasons. Consider the following examples:

$('a').live('click', function() { blah() });
// or
$(document).delegate('a', 'click', function() { blah() });

Speed

The latter is actually faster than the former, because the former first scans the entire document for all $('a') elements, storing them as jQuery objects. Even though the live function only needs to pass ‘a’ through as string argument to be evaluated later, the $() function doesn’t “know” that the chained method is going to be .live().

The delegate method on the other hand, only needs to find and store the $(document) element.

One hack to get around this is to call the live binding outside of the $(document).ready() state, so that it runs immediately. That way it will run before the DOM gets populated, and thus won’t find the elements or create the jQuery objects.

Flexibility and chain-ability

The live function is also convoluted. Think about it; it’s chained to the $('a') object set, but it’s actually acting on the $(document) object. For this reason, it can get hairy trying to chain methods to it. In fact, I’d argue the live method would make more sense as a global jQuery method in the form of $.live('a',...).

CSS selector only

And finally, the live method has a very large shortcoming, and that is that it can only operate on a direct CSS selector string. This makes it very inflexible.

For more on the CSS selector shortcoming, see Exploring jQuery .live() and .die().

Update: Thanks to pedalpete on Hacker News and Ellsass below in the comments for reminding me to add this next section.

Why .live() or .delegate() instead of .bind()

After all, bind seems so much clearer and more direct, doesn’t it? Well, there are 2 reasons we prefer delegate or live to bind:

  • To attach handlers to DOM elements that may not yet exist in the DOM. Because bind directly binds handlers to the individual elements, it cannot bind them to elements that aren’t on the page yet. If you were to run $('a').bind(...), and then new links were added to the page via AJAX, your bind handler would not work for these. live and delegate on the other hand are bound to another ancestor node, so it will work for any element exists now or in the future within that ancestor element.
  • Or to attach a handler to a single element or small group of elements, listening for events on descendent elements, instead of looping through and attaching the same function to 100 individual elements in the DOM. This would be the performance benefit of attaching a handler to one (or a small group of) ancestor element(s) instead of directly attaching handlers to all elements on the page.

Stopping propagation

I’d like to mention one last note concerning event propagation. Typically, we can stop other handler functions from running by using event methods like:

$('a').bind('click', function(e) {
  e.preventDefault();
  // or
  e.stopPropagation();
});

However, when we use the live or delegate methods, the handler function won’t actually run until the event bubbles to the element to which the handler is actually bound. By this time, our other handler functions from .bind() have already run.

75 Responses to “The Difference Between jQuery’s .bind(), .live(), and .delegate()”

  1. Norm says:

    Very good explanation, Steve. Thanks for writing this post.

  2. Klaatu says:

    nice post. thanks for the write up.

  3. Ellsass says:

    One big difference is that

    delegate

    (and, I believe,

    live

    ) will work on elements that are not present when the document loads. That is, if you do

    $('a').bind(...)

    it will not fire on any links that are added to the page later (e.g., via ajax). But

    $('body').delegate('a',...)

    will work on all links at any time, whether they were there from the start or created later on.

    • Naveen Tiwari says:

      Yes correct!
      The .delegate() and .live() are used to bind the events which generates via ajax or later.

  4. Ellsass: Yes! Holy crap, I can’t believe I glazed over that fact, I was so focused on explaining it technically, I forgot to mention the “why”. I’m updating the article now with a small “why delegate/live instead of bind”. Also see my comment on Hacker News concerning this.

  5. Rizky Syazuli says:

    how bout using bind() like this? it’s a bit longer to write. but how’s the speed compare to using delegate()?

    $(document).bind('click', function(e) {
      var target = e.target;
     
      if (target.tagName==='A') {
        // do stuff
      }
    });
  6. Rizky: that’s an interesting question. That is what delegate does logically, though it isn’t how it’s implemented literally. If I had to hazard a guess without testing it, I’d say yours would probably both bind faster (due to use of .bind()) and execute faster (since you’re not using any CSS parsing). However, yours lacks the flexibility to do any more advanced CSS selectors, multiple selectors, etc. without changing your actual handler function.

    Also, take care to use the appropriate target (which you are), in terms of e.target vs e.currentTarget vs e.relatedTarget (see jQuery’s Event object for explanation).

    • Justin Meyer says:

      It will only be faster for a single bind. If you do multiple delegate will be faster.

      • It would only ever be a single bind though, because there is only one $(document) root node.

      • Justin Meyer says:

        I mean if you wanted to do

        $(document).click(function(ev){
          if($(ev.target).closest('div')){...}
        })

        $(document).click(function(ev){
          if($(ev.target).closest('a')){...}
        })

        Using delegate/live will be faster

    • Justin Meyer says:

      Also, that example is not the same as live. It needs to check if the target is within an ‘a’ element. Consider clicking a span inside an ‘a’.

      • Sander says:

        Thanks, very helpful! Had problems before with .bind events not being fired on elements that didn’t existed in the DOM from the beginning.

  7. Graham says:

    Very nice explanation! This is extremely helpful. I’ve used all three (and really like delegate), but I wasn’t exactly sure where it differed from .live(). Thanks.

  8. Clean and helpful as usual.

    I only use some classics binding with the no-xmlHTTPrequest elements, but always live() and also die() on elements from an ajax respond.

    Never heard about delegate() method like this, thank’s for this great post.

  9. James Duvall says:

    Great job. Thanks for tackling this. It makes jQuery that much more inviting when functionality can be so easy explained.

  10. Peter Jaros says:

    Awesome! I didn’t know delegate(). That seems like a much nicer syntax.

    By the way, in your note at then end, e.preventDefault() will still work. Its job is to stop the browser from doing what it normally does in response to an event, like following a clicked link. That action doesn’t happen until all of the JS events are resolved, so we can still cancel it, even from a bubbled handler on document.

    • Good point about preventDefault(). Though, I was referring to the fact that many people will use e.isDefaultPrevented() in their other handlers to determine whether or not to execute their handlers. In that case, e.preventDefault() in a document binding would still prevent the browser from doing it’s thing, but would not prevent their other handlers from executing, since their other handlers would have already been triggered by that point.

  11. Trevor says:

    Thanks Steve. Just what I was looking for. I’ve signed up for your feed. Question. What’s the difference between:

    $('a', $('#container')[0]).live('click', ... );

    and

    $('#container').delegate('a', 'click', ... );
    • Hey Trevor, glad it helped. The difference is that the first function finds every a element within #container and makes a collection of jQuery objects out of them, before simply passing the a selector string on to the .live() method.

      Meanwhile, the second function just turns #container into a jQuery object, and passes the a selector string to the .delegate() method.

      If the first function has to search through a large DOM with lots of links, it will be much slower to initialize.

  12. dev mach says:

    Am i missing something or delegate() and live() aren’t the same thing ? ( just look at the jquery code )

    - ps : please somehow change your spam protection engine. that fucking thing drives me crazy… that’s 5th time i trying to write comment-

    • dev mach says:

      http://code.jquery.com/jquery-1.5.1.js

      ...
          delegate: function( selector, types, data, fn ) {
              return this.live( types, data, fn, selector );
          },
      ....
      • Hey, sorry about the aggressive spam filtering. I tried whitelisting you, but couldn’t find you in the blocked list. Let me know if it happens again and I’ll dig around.

        Delegate and live are not the same thing for the reasons outlined in this post. The live method that .delegate() references is a different function used internally within the jQuery source. You can see that method defined here, while the publicly available .live() method is defined here.

      • dev mach says:

        Thanks for the explanation and links. After reading the code it’s now clear :)

        Spam filtering : Now looks like everthing works. Somehow yesterday, i coudn’t write my comment without fighting :)

      • No prob, I remember that internal method tripped me up the first time I started patching the methods in jQuery. The thing that finally gave it away was that the internal method was called with 4 parameters while the public method accepts 2 parameters, the event and handler function.

  13. Virendra says:

    Awesome article. I found another article which defines the difference between all 3 methods bind, live and delegate.

    http://jquerybyexample.blogspot.com/2010/08/bind-vs-live-vs-delegate-function.html

  14. Andreas says:

    Great overview. Can you shed some light on why rails/jquery-ujs is using .live() instead of .delegate(). .delegate() seems to be a viable, maybe even better choice.

    • It’s using .live() because I’m guessing the original author of the binding section was unaware of .delegate(), as is usually the case.

      Also, none of the downsides applied in this case. We’re only using CSS selectors, we don’t need to chain anything to the binding function, and as of this commit, we’re not waiting for the DOM ready event.

      However, as I’ve pointed out here, .delegate() is just generally better practice, so I’ll probably change it soon.

      Edit: Also, I’ve actually discussed another reason we should probably switch over to .delegate() in this thread.
  15. Louis Foo says:

    Excellent explanation…
    Nice!!!!
    Thank you very much Steve!

  16. Pradeep G says:

    Hi,
    Its just awesome. good that i found it when i started to learn about these.

  17. Chris Khoo says:

    Legend – thanks for that! :-)

  18. nikhil says:

    i need to call a jquery function with many actions.my jquery plugin supports only hover action, i saw the javascript file and found this:
    $(this).hover(function() {…some code}
    so is there a way to tweak this and use it to be called by onhover as well as onfocus??

  19. Lar says:

    excellent article, very concise and easy to read. Finally me – spoiled internet user lazy to read multipage manuals – understood this difference! :) Thanks much, Steve

  20. [...] Today @ 08.57 It's worth knowing that jQuery's live() and delegate() work by using event bubbling. And here's an explanation of the differences between bind(), live(), and delegate(). [...]

  21. Gilles says:

    Nice article, also just wanted to clear that bind can be used for elements that are added after the original page load. You can create an element and bind it before adding it to the document.

    $('').bind('click', clickFunction).appendTo($('body')[0]);

    You don’t even need to add the element to the document for bind() to work.

    $('').attr('src', 'test.jpg').bind('load', function() { alert('I am binded and not in the document'); });

    It is clearer to say that bind will only affect the matched element(s) retrieved by the CSS query at the time of the query. Or to be more exact will only “bind” the set of element(s) it is given (as you could use bind without a CSS query)

    P.S: I know the example I give is not the same case as you are showing but I just wanted to illustrate that saying bind() doesn’t work on element added after the page load was unclear.

    P.S2: Only problem with posts like this, is that many, if not most, of the readers will start using live() and delegate() over bind() for the wrong reasons.

    I think this article could have done with more information on how to pick which method is best for your situation. live() and delegate() are only good to bind dynamic content, if your page doesn’t change it’s not needed and will actual damage performance. (also I am not sure the overhead done by delegate/live everytime something is clicked, is less than the overhead to loop over many elements and bind them individually the first time – performance over time)

    • That is correct, .bind() works on the set of elements present at the time it’s called. I thought that was clear, but perhaps it could have been clearer.

      live() and delegate() are only good to bind dynamic content, if your page doesn’t change it’s not needed and will actual damage performance.

      This is not true. .live() and .bind() are not just for binding dynamic content, they’re good for binding basically any content, and especially when we have a lot of elements already on the page. And they do not damage performance compared to bind, in fact generally quite the opposite.

      They improve performance at bind time (by a large amount when there are a lot of matching elements), which can be done before the document is ready with live and delegate, which means the document loads faster. And they only add a tiny fraction of a performance hit when the person actually clicks or interacts with the element (and when I say tiny fraction, I mean basically imperceptible).

      If you think about it, this makes sense. They improve performance at bind time, because they replace the necessity for .bind() to potentially loop through tens, hundreds, or thousands, of objects, with only binding one function to one object to handle them all. And it only impacts performance very minutely on interaction, because it just needs to do a simple one-time comparison each time the person interacts (i.e. it’s not looping through anything or doing anything repetitively). The one-time comparison it does is usually negligible compared to the function you’re actually binding.

  22. Hi Steve,

    Great explanation!

    I would like the difference when we use:

    $(element).click(function() { bar(); });

    Or is it the same of the .bind()?

    Thanks!

  23. Sean Hogan says:

    Another difference between bind() and live() / delegate() is that for each $(selector).live(type, handler) call, jQuery only calls handler on the $(event.target).closest(selector) element – that is, the nearest matching ancestor-or-self element of the event target.

    (For more details see http://ejohn.org/blog/closestarray-in-jquery-14/)

    This means that:
    - $(“div”).live() can be different to $(“div”).bind() as the former only works for the closest div to the event target
    - Similarly, $(“div, p”).live() can different to $(“div”).live(); $(“p”).live();

    (This comment is largely copied from my somewhat dated stackoverflow answer http://stackoverflow.com/questions/2202367/what-is-the-difference-between-jquery-live-and-livequery-plugin/2204363#2204363)

  24. David Beck says:

    Great Post. Thanks for the clear explanation. Keep up the good work!

  25. Rafael Ulloa says:

    excellent post. very helpful. thanks for sharing.

  26. Nice clear and helpful explanation. It makes it very clear as when to use .live and when not to use it. The explanation of why delegate performs better over live is well described.

    • I don’t think they’ve actually deprecated any of the existing methods of event-binding. In fact, from the linked post:

      Our current event APIs aren’t going away soon, but to address the inconsistencies we’ve introduced a new and simple pair of event methods that can do the work of all three

      And the new API methods, on and off, still require an understanding of live, bind, and delegate, as described here. This new API still has the ability to bind in each of the different methods. The only difference is that you now pass in your preferred method of binding in the arguments to the on method, rather than using three different method names.

  27. LearningEveryday says:

    Beautiful article.
    Can you please provide examples as how .delegate works?
    Whenever I’m using .delegate the following error pops up in firebug:

    $("#mytable").delegate is not a function

    My code:

    $('#mytable').delegate('TH','click',function(){
    alert("Clicked on table header");
    }
  28. LearningEveryday says:

    Got it.
    I was using the .delegate inside .ready function.
    I put it outside, now its working like magic !

    Thank you.
    I have a question though. I have been hearing and reading a lot about discontinuing usage of javascript and JQuery as a whole as these run at browser side,security issue and blah blah blah.
    Is this true?

  29. Carl says:

    Very nice article Steve.

    By starting off with the basics of the DOM event bubbling you’ve really made the explanation of bind(), live() and delegate() so much easier to grasp. Beforehand I just clumped them all together as “event handling stuff” with just the knowledge that bind() attached to existing DOM elements and live() could attach handlers to “future” elements but now I know why and also about delegate() too.

    Of course the new .on() and .off() of jQuery 1.7 have simplified this but it’s good to know where the need for amalgamation of event handling came from too.

    Thanks for taking the time to write this article Steve.

  30. andy schmidt says:

    Thanks, I was binding a click event to the body element inside another click event and wondering why they were both firing. Your explanation made me realize that after the first one fired it bubbled up and triggered the second.

  31. Love the way you wrote this blog post and you took care of a lot future queries while writing the blog itself :)
    Thanx.

  32. Diogo Melo says:

    Hi,

    lets say that i’m using ajaxForm on all my forms and the forms are created dynamically. So it’s not bound with an event**, I just want it to apply to the forms as it is created. Something like:

    $(‘form’).magic(ajaxForm(options));

    and then it runs $(‘form’).ajaxForm(options) and listen for new elements that matches $(‘form’), to run the same ajaxForm.

    I’m not sure if I made myself clean. Is there a way to cope with what I want? Btw, excellent article.

    ** I mean, it’s not to be run in case a click happens, it must run when the element is created.

    • To clarify, .ajaxForm() is from the form.js jquery plugin, not jquery itself. If you just want to bind to an element directly when it is added to the dom, you can just use .bind() when in your code that adds it to the dom.

  33. Ryan Hinton says:

    Excellent post! Very informative, Steve.
    Thank you for the clarification between all of these events.

    Would there be any chance we all could get your understanding in how the operation and mechanics of the ‘on’ event works compared to the other three events?

    • Yes, you can think of on as a sort of meta-function that combines the functionality of all three (well, technically on is now the actual function, delegate defers to on, and live is deprecated). If you check out the docs linked at the top of the article, they have a table that compares the old API and the new API using on.

      If you’re asking for my personal take, I still prefer using bind and delegate, since they’re much more expressive. The new on does a good job of combining 3 different functions that all have closely related intents, but I don’t like that it conflates very different mechanics into almost identical syntax. When I’m writing JS code, I prefer to be able to quickly understand both intent and functionality (i.e. mechanics).

  34. Drew says:

    Great article, makes it very clear what each does. Cheers!

  35. Daniel says:

    Very nice explanation! Thanks from Brazil!

  36. Julie Smith says:

    Excellent article, Steve. Your explanation was very clear and you made it easy to understand.

  37. Sami says:

    What you say about stopping propagation is not correct. For simple test case, have a document that has only one ‘a’ element.
    Then attach two handlers:
    $(‘body’).click(function (ev) { ev.stopPropagation(); });
    $(‘a’).live(‘click’, function (ev) { alert(‘foobar’); });

    Clicking the a-element won’t have an alert box.

    • I actually had this exact same conversation on Reddit a few days ago. You misinterpreted my note about stopPropagation() not working. Sorry for the confusion, but what I mean by the statement that, calling stopPropagation() in a delegated handler is too late to actually stop it, is this:

      Yes, if you call stopPropagation on one delegated event, then it will prevent a parent delegated handler from firing, but what I was saying is it won’t prevent that event from firing on the parent. If that’s confusing, see my updated example: http://jsfiddle.net/84dZe/5/

      Notice that testDiv2 direct still fires even though you called stopPropagation on the testButton2 click event.

      If it’s still confusing, it might help to just look at the source code. All stopPropagation does is sets event.isPropagationStopped = true, and then if the event has an associated originalEvent, it calles stopPropagation on that too. (see source)

      Then, all subsequent bindings check to see if isPropagationStopped set to true before firing the handlers. But that won’t get set until after the original event has already propagated to the top of the DOM, since you’re calling it in a delegated handler.

      Typically I would avoid code like that altogether, because it’s unclear what the intention is. One way to accomplish something similar, which is clearer and more explicit would be something like this: http://jsfiddle.net/84dZe/6/

      Now it’s clear that in this instance, you only want the second event to fire if the div itself is clicked.

      • Vishal says:

        Very well explained, i don’t understand it completely though but that’s my problem. And wonderful article.

        A Big Thanks :)

  38. Sreekanth says:

    Nice and clear explanation…….

  39. Mohan says:

    Great Job… Steve
    Keep up the good work!!!

  40. pomeh says:

    Very nice article ! Thanks for sharing it. I will use it for future reference, for sure :)

    But I have two comments to do.
    First of all, is it possible to update the article to mention the new

    $.fn.on

    method and the deprecation of

    $.fn.live

    since jQuery 1.7 ?
    Secondly, the part about using

    $(document).ready()

    to “run [the code] before the DOM gets populated” is not accurate. Depending on where the script tag is positioned in the HTML source code, the usage of

    $(document).ready()

    is not needed. Check the demo on jsfiddle http://jsfiddle.net/pomeh/PYa9N/.

    Cheers !
    pomeh

    • Thanks for the comments. The article already has a mention of the new $().on function at the top. The part about using $().live outside $(document).ready assumes the javascript is in a script in the head section of the document.

      • pomeh says:

        Thanks for the reply.
        In most cases, script tags should not be placed in the head section, this is considered as a bad practice. So I think this relation between

        $(document).ready

        and

        $.fn.live

        to “improve the speed” sounds like a bad shortcut and thus a bad advice to me. And this is also one of the reason why delegate is better and why live has been deprecated and will be removed in a future version.

      • If you’re talking strictly about script tags placed directly in your html document, then yes, but I was referring to javascript in an external javascript file, which is usually where you would write your javascript. And links to external js files are usually in the head section.

Leave a Reply

You may include code snippets in your comment using this syntax.