What is the correct way to write HTML using Javascript?

143,818

Solution 1

document.write() will only work while the page is being originally parsed and the DOM is being created. Once the browser gets to the closing </body> tag and the DOM is ready, you can't use document.write() anymore.

I wouldn't say using document.write() is correct or incorrect, it just depends on your situation. In some cases you just need to have document.write() to accomplish the task. Look at how Google analytics gets injected into most websites.

After DOM ready, you have two ways to insert dynamic HTML (assuming we are going to insert new HTML into <div id="node-id"></div>):

  1. Using innerHTML on a node:

    var node = document.getElementById('node-id');
    node.innerHTML('<p>some dynamic html</p>');
    
  2. Using DOM methods:

    var node = document.getElementById('node-id');
    var newNode = document.createElement('p');
    newNode.appendChild(document.createTextNode('some dynamic html'));
    node.appendChild(newNode);
    

Using the DOM API methods might be the purist way to do stuff, but innerHTML has been proven to be much faster and is used under the hood in JavaScript libraries such as jQuery.

Note: The <script> will have to be inside your <body> tag for this to work.

Solution 2

document.write() doesn't work with XHTML. It's executed after the page has finished loading and does nothing more than write out a string of HTML.

Since the actual in-memory representation of HTML is the DOM, the best way to update a given page is to manipulate the DOM directly.

The way you'd go about doing this would be to programmatically create your nodes and then attach them to an existing place in the DOM. For [purposes of a contrived] example, assuming that I've got a div element maintaining an ID attribute of "header," then I could introduce some dynamic text by doing this:

// create my text
var sHeader = document.createTextNode('Hello world!');

// create an element for the text and append it
var spanHeader = document.createElement('span');
spanHeader.appendChild(sHeader);

// grab a reference to the div header
var divHeader = document.getElementById('header');

// append the new element to the header
divHeader.appendChild(spanHeader);

Solution 3

  1. DOM methods, as outlined by Tom.

  2. innerHTML, as mentioned by iHunger.

DOM methods are highly preferable to strings for setting attributes and content. If you ever find yourself writing innerHTML= '<a href="'+path+'">'+text+'</a>' you're actually creating new cross-site-scripting security holes on the client side, which is a bit sad if you've spent any time securing your server-side.

DOM methods are traditionally described as ‘slow’ compared to innerHTML. But this isn't really the whole story. What is slow is inserting a lot of child nodes:

 for (var i= 0; i<1000; i++)
     div.parentNode.insertBefore(document.createElement('div'), div);

This translates to a load of work for the DOM finding the right place in its nodelist to insert the element, moving the other child nodes up, inserting the new node, updating the pointers, and so on.

Setting an existing attribute's value, or a text node's data, on the other hand, is very fast; you just change a string pointer and that's it. This is going to be much faster than serialising the parent with innerHTML, changing it, and parsing it back in (and won't lose your unserialisable data like event handlers, JS references and form values).

There are techniques to do DOM manipulations without so much slow childNodes walking. In particular, be aware of the possibilities of cloneNode, and using DocumentFragment. But sometimes innerHTML really is quicker. You can still get the best of both worlds by using innerHTML to write your basic structure with placeholders for attribute values and text content, which you then fill in afterwards using DOM. This saves you having to write your own escapehtml() function to get around the escaping/security problems mentioned above.

Solution 4

Perhaps a good idea is to use jQuery in this case. It provides handy functionality and you can do things like this:

$('div').html('<b>Test</b>');

Take a look at http://docs.jquery.com/Attributes/html#val for more information.

Solution 5

You can change the innerHTML or outerHTML of an element on the page instead.

Share:
143,818
Gary Willoughby
Author by

Gary Willoughby

Software engineer and published author with over twenty years experience of software design and development.

Updated on July 05, 2022

Comments

  • Gary Willoughby
    Gary Willoughby almost 2 years

    It seems that experienced web developers frown upon using document.write() in JavaScript when writing dynamic HTML.

    Why is this? and what is the correct way?

  • Maiku Mori
    Maiku Mori over 14 years
    It's actually executed when you call it. If you call it after the page has loaded it will overwrite the content.
  • Maiku Mori
    Maiku Mori over 14 years
    You can use it, try it =). It's probably not what you want to do, but still you can.
  • Maiku Mori
    Maiku Mori over 14 years
    If you write dynamic components using javascript you will end up writing to DOM with javascript. While document.write() isn't really the way to go you will probably use innerHTML in most cases. Since innerHTML is a lot faster then using createNode/appendChild in all browsers. It's quite important when you have to generate a lot html/DOM elements. + it's document, not documment ;)
  • Amit Patil
    Amit Patil over 14 years
    Preferably innerHTML, as outerHTML isn't widely supported.
  • Gary Willoughby
    Gary Willoughby over 14 years
    A nice full answer, thankyou. I understand now that document.write() only is useful for when the page is loading and being created for the first time. For dynamically updating the page afterwards the DOM methods or innerHTML() are a must.
  • Tim Down
    Tim Down over 14 years
    Stick to HTML and document.write remains a useful tool.
  • Tim Down
    Tim Down over 14 years
    Could you provide proof that innerHTML is always faster? I would doubt it's always the case. If you add nodes one at a time to an existing node in the DOM then I expect innerHTML is faster, since the browser potentially has to manipulate and re-render parts of the document at every stage, but if instead you create a new node tree and add its root node to the DOM at the end, I would expect that to be as fast or faster than using innerHTML.
  • Ricky
    Ricky over 14 years
    @Maiku - LOL, true that :) @Tim - Here is a benchmark quirksmode.org/dom/innerhtml.html And actually, using document fragments seems to be the fastest : ejohn.org/blog/dom-documentfragments
  • Tim Down
    Tim Down over 14 years
    @Ricky - thanks, interesting reading. Both linked articles are flawed: the quirksmode example is quite old, so is not tested against the most recent major version of any of the browsers and in IE's case the last two major versions (note that he tested against IE7 beta 3, not the final release). However, it does prove your point for IE6 and his example. John Resig's example, on the other hand, is extremely flawed and proves nothing, as the comments for the article show.
  • Ricky
    Ricky over 14 years
    @Tim - This day in age, I think we should just trust the frameworks to do this low level DOM stuff for us. Hopefully, they know more than we do :)
  • Tim Down
    Tim Down over 14 years
    @Ricky - I've looked in depth at the code for some of these libraries and I wouldn't be so sure.
  • domen
    domen over 10 years
    node.innerHTML = '<p>some dynamic html</p>'; ? At least on WebView on Android innerHTML is not a function.
  • Lennon
    Lennon over 10 years
    Firefox doesn't support innerHTML nor outerHTML.
  • Lennon
    Lennon over 10 years
    Because people are talking about the more elegant, faster and cross-browser way of doing something, and having to load jQuery to achieve it, is not an answer.
  • Firebirdz
    Firebirdz over 10 years
    var node = document.getElementById('node-id'); node.innerHTML('<p>some dynamic html</p>'); This does not work for me, I used document.getElementById("node-id").innerHTML = "<p>some dynamic html</p>"; (firefox)
  • gagarine
    gagarine almost 9 years
    @domen it's certainly because your element doesn't exsite when you call innerHTML. See stackoverflow.com/questions/10826756/…
  • Normajean
    Normajean almost 4 years
    According to my browser, node.innerHTML('<p>some dynamic html</p>') is not a function and needs to be written as node.innerHTML = '<p>some dynamic html</p>'