Clearest way to build html elements in jQuery

JavascriptJqueryCoding StyleElement

Javascript Problem Overview


I've seen a lot of different styles (and few different methods) of creating elements in jQuery. I was curious about the clearest way to build them, and also if any particular method is objectively better than another for any reason. Below are some examples of the styles and methods that I've seen.

var title = "Title";
var content = "Lorem ipsum";

// escaping endlines for a multi-line string
// (aligning the slashes is marginally prettier but can add a lot of whitespace)
var $element1 = $("\
    <div><h1>" + title + "</h1>\
        <div class='content'>  \
        " + content + "        \
        </div>                 \
    </div>                     \
");

// all in one
// obviously deficient
var $element2 = $("<div><h1>" + title + "</h1><div class='content'>" + content + "</div></div>");

// broken on concatenation
var $element3 = $("<div><h1>" +
                title + 
                "</h1><div class='content'>" +
                content +
                "</div></div>");

// constructed piecewise
// (I've seen this with nested function calls instead of temp variables)
var $element4 = $("<div></div>");
var $title = $("<h1></h1>").html(title);
var $content = $("<div class='content'></div>").html(content);
$element4.append($title, $content);

$("body").append($element1, $element2, $element3, $element4);

Please feel free to demonstrate any other methods/styles you might use.

Javascript Solutions


Solution 1 - Javascript

Templates are great and if you have access to them in your project, I suggest you use them. If you're using Underscore or Lodash it's built in. In some cases however, you will need to build HTML in your code whether it's refactoring or testing. I've found that the below format is the clearest to read when that is the requirement.

Note: The HTML spec allows single OR double quotes for attributes in your markup so don't bother with all the crazy escaping.

this.$fixture = $([
  "<div>",
  "  <div class='js-alert-box'></div>",
  "  <form id='my-form-to-validate'>",
  "    <input id='login-username' name='login-username'>",
  "  </form>",
  "</div>"
].join("\n"));

Solution 2 - Javascript

After looking around for a while, I found the style which I finally settled on. First, I'll say that I used Mustache for templating, and it worked well. Sometimes, though, you just need to build an element one time, without reusing it, or have some other motivation to not bring in another library. In this situation, I have taken to using:

$("body")
.append(
    $("<div>")
    .append(
        $("<div>")
        .append(
            $("<h1>").text(title)
        )
    )
    .append(
        $("<div>").text(content)
    )
);​

This works because append() returns a reference to the object you're appending to, so chained append()s attach to the same object. With proper indentation, the structure of the markup is obvious, and this way it's easy to modify. Obviously this is slower than using templates (the whole thing has to be built piece by piece), but if you're only using it for initialization or something similar then it is a great compromise.

There are many ways one could format a construct like this, but I've chosen a way to make it clear what's going on. The rule I used is that there should be a maximum of one opening parenthesis and/or one closing parenthesis on each line. Also, the leaves of these append trees do not need to be passed to the jQuery constructor, but I've done so here for visual repetition.

Solution 3 - Javascript

When it comes to DOM building I try to avoid string concatenations as they might lead to subtle bugs and non properly encoded output.

I like this one:

$('<div/>', {
    html: $('<h1/>', {
        html: title
    }).after(
        $('<div/>', {
            'text': content,
            'class': 'content'
        })
    )
}).appendTo('body');

generates:

    ...
    <div><h1>some title</h1><div class="content">some content</div></div>
</body>

and it ensures proper HTML encoding and DOM tree building with matching opening and closing tags.

Solution 4 - Javascript

My advice : don't try to build html elements with jQuery, it's not its responsability.

Use a Javascript templating system like Mustache or HandlebarJs.

With a very limited number of line, you can create your html elements directly from a Javascript object. It's not complicated, only 2 functions and a template.

<div class="entry">
  <h1>{{title}}</h1>
  <div class="body">
    {{body}}
  </div>
</div>

var context  = {title: "My New Post", body: "This is my first post!"}
var template = Handlebars.compile($("#template-skeleton"));
var html     = template(context);

Edit:
Another example without html, pure Javascript (from ICanHaz) :

var skeleton = '<div><h1>{{title}}</h1><div class="content">{{content}}</div></div>';
var data = { title: "Some title", content: "Some content" };
var html = Mustache.to_html(skeleton, data);

It is much more maintainable than a series of concatenation.

Solution 5 - Javascript

2015 answer:

For ES6, use JavaScript template strings

var str = `
<!doctype html>
<html>
    <body>
        <h1>❤ unicorns</h1>
    </body>
</html>`

For older browsers, use multiline.

var str = multiline(function(){/*
<!doctype html>
<html>
    <body>
        <h1>❤ unicorns</h1>
    </body>
</html>
*/});

Solution 6 - Javascript

This is adapted from Baer's answer. I find it more readable, no need to create and join an array, no need to put quotes around every line:

http://jsfiddle.net/emza5Ljb/

var html =

	'                                                           \
	  <div>                                                     \
	    <div class="js-alert-box"></div>                        \
	    <form id="my-form-to-validate">                         \
	      <input id="login-username" name="login-username">     \
	    </form>                                                 \
	  </div>                                                   	\
	'
	
// using jQuery:
//
var dom = $( html )

// or if you need performance, don't use jQuery
// for the parsing.
// http://jsperf.com/create-dom-innerhtml-vs-jquery
//
var div       = document.createElement( 'div' )
div.innerHTML = html
var dom = $( div )

FYI, when performance isn't an issue and elements contain a lot of dynamic data, I sometimes just write code like this (note that closure compiler will throw a warning about the unquoted class property, but in modern browsers this works fine):

$(
	  '<a></a>'

	, {
	       text     : this.fileName
	     , href     : this.fileUrl
	     , target   : '_blank'
	     , class    : 'file-link'
	     , appendTo : this.container
	  }
)

Solution 7 - Javascript

Here's an example that uses $(htmlString) and mimics the standard layout of HTML code:

function getPage(title, contents) {
  return (
    $("<div>", {id: "container", class: "box"}).append(
      $("<div>", {class: "title"}).append(
        $("<h1>").text(title)
      ),
      $("<div>").html(contents)
    )
  );
}

Solution 8 - Javascript

Solution 9 - Javascript

I find the functional approach very convenient. For instance

// reusable generics TABLE constructor helpers
var TD = function(content) { return $('<td>', { html: content }) }
var TH = function(content) { return $('<th>', { html: content }) }
var TR = function(cell, cells) {  // note the kind of cell is a 2^order parameter
    return $('<tr>', { html: $.map(cells, cell) })
}

// application example
THEAD = $('<thead>', {html:
    TR(TH, [1,2,3,4])})
TBODY = $('<tbody>', {html: [
    TR(TD, ['a','b','c','d']),
    TR(TD, ['a','b','c','d']),
]})

now the call

$('#table').append($('<table>', {html: [THEAD, TBODY]}))

yields

<table><thead><tr><th>1</th><th>2</th><th>3</th><th>4</th></tr></thead><tbody><tr><td>a</td><td>b</td><td>c</td><td>d</td></tr><tr><td>a</td><td>b</td><td>c</td><td>d</td></tr></tbody></table>

edit

I have refined my approach, now available for instance as html_uty.js

Solution 10 - Javascript

Simplest way of doing this using backticks -

var optionsForLength =  `
    <option value="Kilometre">Kilometre</option>
    <option value="Metre">Metre</option>
    <option value="Centimetre">Centimetre</option>
    <option value="Milimetre">Milimetre</option>
    <option value="Micrometre">Micrometre</option>
    <option value="Nanometre">Nanometre</option>
    <option value="Mile">Mile</option>
    <option value="Yard">Yard</option>
    <option value="Foot">Foot</option>
    <option value="Inch">Inch</option>
`;

Or you can use single quotes as well to wrap your HTML inside javascript -

var optionsForLength = 
'<option value="Kilometre">Kilometre</option>'+
'<option value="Metre">Metre</option>'+
'<option value="Centimetre">Centimetre</option>'+
'<option value="Milimetre">Milimetre</option>'+
'<option value="Micrometre">Micrometre</option>'+
'<option value="Nanometre">Nanometre</option>'+
'<option value="Mile">Mile</option>'+
'<option value="Yard">Yard</option>'+
'<option value="Foot">Foot</option>'+
'<option value="Inch">Inch</option>'+
'<option value="Nautical mile">Nautical mile</option>';

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionbkconradView Question on Stackoverflow
Solution 1 - JavascriptBaerView Answer on Stackoverflow
Solution 2 - JavascriptbkconradView Answer on Stackoverflow
Solution 3 - JavascriptDarin DimitrovView Answer on Stackoverflow
Solution 4 - JavascriptJulien LafontView Answer on Stackoverflow
Solution 5 - JavascriptmikemaccanaView Answer on Stackoverflow
Solution 6 - Javascriptuser1115652View Answer on Stackoverflow
Solution 7 - JavascripttoklandView Answer on Stackoverflow
Solution 8 - JavascriptStraseusView Answer on Stackoverflow
Solution 9 - JavascriptCapelliCView Answer on Stackoverflow
Solution 10 - JavascriptMuhammad TariqueView Answer on Stackoverflow