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:



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) {

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 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.

    • 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.

  • 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.

    • 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.

  • 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:
    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

    • 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.

    • 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 :)

    • 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!

    • bellasys

      actually, according to modern journalistic stylesheets, including newscaster’s style manuals, dropping the -ly is now acceptable, and is considered representative of modern American english. However, ie6 may still turn its nose up at this.

  • Neil

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

  • Derek

    May God bless you also!

  • jwa107

    If this was their intention why would they not write:

    if (typeof elem === ‘function’) {



    It would seem that this would force the user into spec. Rather if(elem) simply checks if something is there.

    What I mean is, I disagree with your assessment. The specs say they accept and “htmlString” which is defined by Jquery here:

    This clearly shows DOM elements inside a string, which could semantically be argued is different from passing DOM directly in, though you could toString it and it would be the same.

    • Joe Zimmerman

      You can interpret it however you want, but I was explicitly told by a jQuery developer that the html method does not officially support DOM elements or jQuery objects. Go ahead and use it however you like. I highly doubt they’ll change the implementation in a way that will break that support.

      • Joshua Micheal

        Since 1.4 it has accepted a string OR a function (jquery element). it is is in the docs.

        • Joe Zimmerman

          The jQuery docs mention that you can use a function that returns an HTML string. DOM elements and jQuery objects are not functions, let alone functions that return strings of HTML.

          A function is an object, but not all objects are not functions. `x = {}; x()` and `x=$(‘#id’); x()` will return `TypeError`s because `x` is not a function in either case.

          Also, the docs don’t mention `.empty().append()`, they mention `.empty().html()`. The docs don’t mention `.empty().append()` because the docs for `.html()` don’t mention anything about being able to use a DOM element or jQuery object, so they don’t presume that you’ll think you can. `.html()` is for injecting HTML strings and is essentially just a replacement for `innerHTML`, which only accepts strings.

          • Joshua Micheal

            The implementation of html() is not essentially just doing innerHTML. Read the source. Half of it’s implementation is the part where it checks if you’re passing in a DOM element, function, jquery object, string, and converting to an HTML string (line 5301). Then based on the browser, only sometimes does it use innerHTML to update the DOM. This is still the same today on jQuery 2.1.4

          • Joshua Micheal

            I get what you’re saying & I guess I was wrong about jquery objects being functions; but I still maintain that using undocumented features does NOT make someone a bad developer.

            Your argument was that we shouldn’t use the undocumented feature because it might break upon upgrade.

            I feel that your argument is flawed because even documented features change in newer versions, which can break your code. Regardless of if you use a library as documented or not, the behavior can change in the new version.

            One thing that good developers do is write automated tests that notify of them of BC breaks, whether that BC break was due to a documented change or an undocumented one.

            If anything the jQuery developers are “Bad” developers for having undocumented features & not defensively programming against passing the wrong inputs; or documenting all the ways that the code currently behaves. I’m half kidding, but just use it how you want, & write automated tests.

            • Joe Zimmerman

              While much of what you say here is true (especially using your own tests to ensure the functionality remains the same throughout version upgrades), you also have to think about this semantically: the html function is for replacing the inner HTML of an element with the given HTML, not for injecting elements. The semantic, correct, and intended way of replacing the contents of an element with a given element is to use .empty().append().

              Also note: I wasn’t calling everyone who uses html() a bad developer. I was jokingly calling *myself* a bad developer because I didn’t know this and the fact that everyone was using html() improperly is due to lack of knowledge and/or wrong knowledge gained from around the internet. The intention of this post was to get the correct knowledge out there and stop propagating an improper and undocumented use of common library’s function. I certainly won’t call you a bad developer if you use html incorrectly without knowing you’re doing anything wrong, but if you’re purposefully using html improperly, I might call you a lazy programmer because that’s the only reason I can see anyone purposefully doing it. I won’t force you to go back and change all the instances of html being used wrong either, but a wise developer should do it the semantic and intended way moving forward.

              • Joshua Micheal

                The only “proper” code, objectively speaking, is code that is tested to work. Using .html() to replace an element’s contents with another element [happens to] work. If you’re writing tests, and your code works – I’d hardly call that lazy or unwise. Your code could be a Rube Goldberg machine behind the scenes, as long as it works & has tests it is good code.

                I do agree though, that most developers should follow your advice, because in reality most developers probably will not take the time to write tests.

                You have to admit though, jQuery could break the undocumented features of .html(), but its also possible they suddenly decide to make the current behavior “official” & documented. Either way, any code you write against someone’s API is a gamble, they can change anything at any time.

  • Danny

    Um, if you look at the documentation, it DOES support passing in an HTML string.

    • Joe Zimmerman

      That’s not in dispute. Please read the article:

      “That’s right, html doesn’t accept anything except strings.”

  • HotDang

    Turns out it has to be valid HTML. What a load.

  • Murali Mohan

    Thanks a lot dude… Very useful trick. I was banging my head why my code was not working in IE. This trick is extremely useful in IE.

  • Chris Gilbert

    bravo man! couldnt understand why jq 2.0.2 broke my code…now i know

    • Joe Zimmerman

      I don’t think this has anything to do with your broken code. jQuery 2.0.3 and 2.1.3 both continue to have the .empty().append() catchall at the end of the html method.