You’re Using jQuery.html() Wrong!

jQuery.html(): You're Doing it WrongWell, you probably are doing it wrong. jQuery's html function is a very nice way to replace the contents of an element with new contents. Its usefulness is supposedly limited, though, according to the API documentation for this method. Every day jQuery users use this powerful method in a way that it was never meant to be used, and it works, but does that mean we should still do it?

What Am I Doing Wrong?

If you take a look at jQuery's API Documentation for the html function, you'll see that it has 3 method signatures. The first method signature has no arguments, so it'll just return the HTML within that element. The other two signatures take a single argument: a string or a function that returns a string. Wait! It doesn't take a DOM element? or a jQuery object? That's right, html doesn't accept anything except strings.

How I Learned That I Am a Bad Programmer

Instead of just telling you what you should be doing instead or why html still works when you send in elements, I'm going to walk you down my path of discovery. It all started last week when I was exploring LayoutManager for Backbone. I was looking through the code that was generated using the Backbone Boilerplate utility for Node.js to give myself a better idea of how LayoutManager is used, when I saw this little snippet of code:

$("#main").empty().append(layout.el);

Confusion

I thought to myself, "Why didn't they just use $('#main').html(layout.el);?" This puzzled me for a bit since I had recently learned (as shown in the Subview Rendering Trick article) that html first calls empty within itself, so there was nothing gained except maybe making it a little clearer that empty is called. Well I shirked that off to the side and decided not to think much of it until I came across the same code within the documentation for LayoutManager. So I decided to ask the developer why he would use empty().append() rather than html(). I was pointed to an article that the author had written about how html didn't support this method signature.

Checking Out the Source

I checked it out myself, and sure enough the jQuery documentation did not support this signature. Well, if it doesn't support the signature, then why does it still work? I decided to use James Padolsey's jQuery Source Viewer to look into it. Here's a stripped down version of the source for html:

function (value) {
    var elem = this[0] || {};

    if (value === undefined) {
        return /* HTML string */;
    }
    if (typeof value === "string" && /* Looks like HTML code*/) {
        //Use `cleanData` and `innerHTML`
        elem = 0;
    }
    if (elem) {
        this.empty().append(value);
    }
}

Remember, this is just a gist of what the source looks like for html. If you want to see the full source you can go here.

Let's walk through this code for a bit. First it sets elem to either the first element in its list of elements or an empty object. Then it checks to see if you passed in any arguments and sends back an HTML string if you didn't. Then it checks if we passed in a string. If we did, then it uses cleanData to remove event handlers and extra data bound to the elements, then insert the new contents via innerHTML. Then, if elem is truthy (it was set to zero at the end of the last if statement to prevent this from being true), then that means that the argument was neither undefined or a string (so it should be a function), so we'll run it through empty().append(value).

The Realization

Well, that means it DOES support DOM elements and jQuery objects because append does! Not only is this true, but since we're using append to catch the case where the argument was a function, why do we bother using the second if statement? We can use append for the cases where it's a string too! Wouldn't this be a great case of DRY (Don't Repeat Yourself)? Well that's what I think anyway.

The jQuery Guy

I decided to put an issue up on the API's GitHub area letting them know how I felt about this. At the time of this writing, I haven't received a reply, but on the previous conversation (the one that I had with the author of LayoutManager) a jQuery team member posted this:

That will get you into trouble. Just because jQuery is open source does not mean that nuances of the current source code define the API. That is what http://api.jquery.com does. Every major release, we have people complain that we "broke their code" because we changed undocumented internals, precisely because they figured they could just read the source and expect it to work that way in future versions.

While he does have a point, I don't see why they would make changes in a way that would remove empty().append() from there.

The "Right" Way

As much as I love how simple it is to use html to insert DOM nodes and jQuery objects, I have to concede that it just isn't "right". If you want to keep checking the source code each time there's an update to make that the new version still uses .empty().append() in there, then by all means keep sending in those nodes and objects. But as a "good" JavaScript programmer, I should – and you should – start using .empty().append(). God bless and happy coding.

About the Author

Author: Joe Zim

Joe Zim

Joe Zimmerman has been doing web development ever since he found an HTML book on his dad's shelf when he was 12. Since then, JavaScript has grown in popularity and he has become passionate about it. He also loves to teach others though his blog and other popular blogs. When he's not writing code, he's spending time with his wife and children and leading them in God's Word.


  • Francisc

    Please add ‘http://’ in front of links that don’t have it.

    • http://www.joezimjs.com Joe Zimmerman

      Sorry about that. I just took care of it.

  • Sébastien Lavoie

    The jQuery team is usually not kind with the devs that use undocumented feature. This will be especially true with the coming of 1.9 and 2.0 where a lot is getting rewritten. Stick to the API documentation.

  • http://twitter.com/mekwall Marcus Ekwall

    Not to sound like a grumpy old man, but the title of this article implies that it is wrong no matter how or when. It’s great that you are spreading this knowledge, but I’d prefer if you change the title into something less sensational. There’s nothing wrong in using .html(), as long as you do it according to the docs. If people have a hard time distinguishing the differences between the DOM manipulation methods, the title will most likely confuse them even further, and that’s kind of contraproductive.

    • http://www.joezimjs.com Joe Zimmerman

      You’re right. I’ll go ahead and change it. As everyone knows, titles are what draw people in and sometimes it’s hard to see how sensational something is from the perspective of the writer. Sorry to give everyone the wrong impression.

  • http://twitter.com/dmackintosh88 David Mackintosh

    I’m actually with Marcus on this, the title is a bit too sensationalised but the article was generally cool. I personally use $().empty().append() but if it’s just a text node I will use html(”)

  • zak

    I started jQuery yesterday (today is Wednesday Aug 22). I am trying to do the following:
    $(‘#divID’).html(“….if(arguments[2]….”);
    From what I understood, I can’t do that. is there another way?
    I am trying to see if I need to create another row for arguments[2] or not.

    Thank you so much

    • http://www.joezimjs.com Joe Zimmerman

      I’m not sure I understand. Can you please send me the full code? You can use the contact form on this site.
      Looking at your code, I see that you’re trying to do an if statement within a string. First of all, build the string up outside of the html function call and store it in a variable. Then us the if statement to append more to the variable if need be.

  • Jeff Adams

    As the saying goes, pave the cow paths. This is such a common use for .html() that perhaps the jQuery team should codify it officially.

    • http://www.joezimjs.com Joe Zimmerman

      Agreed. The library should adapt to its users the best that it can, but until it does, we should still use it as intended.

  • Nick

    Just BTW, your title needs “wrongly” rather than “wrong” to be grammatically right :)

    • http://www.joezimjs.com Joe Zimmerman

      You’re correct. When I use the adverb at the end of the phrase like that, I tend to miss that. Oh well. I don’t think I’ll change it, but thanks for the heads up. Gotta love grammar nazis!

  • Neil

    Informative article. I’ve been a bad programmer for some time now ;-) Time to change my ways I suppose…