Building HTML in jQuery and JavaScript

July 08, 2010

It can be a pain to create HTML elements in JavaScript. In this article I will outline a few ways I deal with HTML. First, we’ll look at whether to use an HTML string or a jQuery object, then look at my little HTML string builder utility and finally get some links to templating libraries for building more complex HTML.

HTML String, or jQuery Object?

The first question you have to ask yourself is whether or not it makes sense to build out HTML as jQuery objects, or if you require the speed of building strings. In jQuery 1.4 you can built HTML objects that have events attached. Consider the following code.

$("input", {
  id: "permissionsInput",
  name: "permissions",
  type: "checkbox", 
  click: function(){
    update();
  },
  checked: "checked"
}).appendTo("#myForm");

You can see here that not only can you build out HTML with attributes, but you can attach events (like click) too. This ability was added to jQuery in version 1.4.

If you were doing this 100 times though, it might be very slow. The better way to do it would be to build out the HTML strings first, and then attach events later with jQuery’s live or delegate methods.

Building HTML Strings

So now you want to build an HTML string because you have a lot of elements to build and you can attach events later. There are basically two ways to do this. You can build one long HTML string and append it:

var data = ["a", "bunch", "of", "things", "to", "insert"];
var html = '';
for (var i=0; i < data.length; i++) {
  html += "<td>" + data + "</td>";
}
$("#tablerow").append(html);

Or you can use an array which is typically a little faster.

var data = ["a", "bunch", "of", "things", "to", "insert"];
var html = [];
for (var i=0; i < data.length; i++) {
  html[html.length] = "<td>" + data + "</td>";
}
$("#tablerow").append(html);

Building Complex HTML Elements

When you are building more complex HTML, things get a little hairy in the code. Take our previous example with jQuery and turn it into raw HTML building:

html = '<input id="permissionsInput" name="permissions" type="checkbox" checked="checked">';

Not bad, but what if those attributes were set programmatically? This is typical.

html = '<input "' + inputId + '" name="' + inputName + '" type="' + inputType + '"' + (isChecked ? 'checked="checked"' : '') + '/>';

Yuck! So to solve this I wrote a little ditty function called buildHTML. The code isn’t perfect and it could be written better (please do) but it looks like this:

// my little html string builder
buildHTML = function(tag, html, attrs) {
  // you can skip html param
  if (typeof(html) != 'string') {
    attrs = html;
    html = null;
  }
  var h = '<' + tag;
  for (attr in attrs) {
    if(attrs[attr] === false) continue;
    h += ' ' + attr + '="' + attrs[attr] + '"';
  }
  return h += html ? ">" + html + "</" + tag + ">" : "/>";
}

So now our code for building that same input becomes:

html = buildHTML("input", {
  id: inputId,
  name: inputName
  type: inputType
  checked: isChecked
});

Nicer, huh? Get the gist for buildHTML and examples. And by all means fork it and make it better.

Templating

Another way to build out more complex HTML is using templating. John Resig has a great article and some code examples for JavaScript Micro Templating

There is a templating language called mustache that I see a lot of people using. Also, there has been some proposals for templating being built into jQuery’s core, however for now there is a jQuery plugin on github jquery-tmpl. Rey Bango wrote an article explaining using jQuery templating.

If you have any other HTML building tips, please share!

10 comments

#1. JimB on July 08, 2010

i suppose i’ll be marginally helpful, http://github.com/fernmicro/JUP

#2. James on July 08, 2010

HTML building with JS will forever be a topic of much dispute. I don’t know which approach is best but I think the only appealing aspect of HTML strings is the speed offered by the way jQuery plays with innerHTML and document fragments. I agree with you — beyond that, long HTML strings are YUCK!

I like your approach, but it does need some refining :)

A slight improvement on this:

if (attr == 'selected' && attrs[attr] == false) continue;
if (attr == 'disabled' && attrs[attr] == false) continue;
if (attr == 'checked' && attrs[attr] == false) continue;

Combining conditions (plus strict equality check) and using regex to test for attr value:

if (attrs[attr] === false && /^(?:select|disabl|check)ed$/.test(attr)) continue;

Actually, since there are so many other boolean attributes (isContentEditable, autoplay, async, draggable, defer … most of these are HTML5), it might be better to just assume if attrs[attr] is a boolean then attr is a boolean property:

if(attrs[attr] === false) continue;
#3. Marc Grabanski on July 08, 2010

Thank you James! I’ve updated the buildHTML function and the gist in the article.

#4. Agos on July 08, 2010

That buildHTML function is horrible… and pointless, since with jQuery 1.4 you can pass attributes directly to the jQuery function when building HTML.

#5. Stepan Reznikov on July 08, 2010

How about client-side XSLT? When you need to generate large amounts of HTML on the client and this process involves complex logic, then I think XSLT is very handy.

#6. Marc Grabanski on July 08, 2010

Argos, the buildHTML function is for building strings in a sane manner, you don’t get the same performance building jQuery objects.

#7. Dave Ward on July 09, 2010

jQuery 1.4+ automatically caches the DOM fragment created when you go the $(‘’) route, which is supposed to speed that up significantly on loops. As long as you don’t insert the elements into the DOM until you’ve generated them all, it shouldn’t be that slow.

It would be interesting to see some benchmarking between the two approaches.

#8. Marc Grabanski on July 09, 2010

jQuery 1.4 uses document fragment caching if you are inserting the same exact html you’ve inserted before. If you are setting attributes dynamically from JavaScript to built the html then there is no way to cache a bunch of unique elements.

#9. Dave Ward on July 10, 2010

The way I’ve heard John explain it, I was under the impression that if you do this:

$('<div>;', {
  id: 'foo'
});

And then:

$('<div>', {
  id: 'bar'
});

The second div would still be built from a cached fragment before adding those properties to it.

#10. Marc Grabanski on July 10, 2010

Yeah that is true, but you are still doing two processes by building that second object so it isn’t a 100% cached fragment. You are much better off building a string.

Leave a comment

Comment in textile images by gravatar