Fixing innerHTML

I presented my Brighton Ajax workshop yesterday. It all went rather smoothly. The workshop was in the same swanky building as the Clearleft office so I felt like I was playing on home turf. The homely feel was emphasised with the choice of snacks: Jessica was kind enough to bake up a whole batch of cookies for the workshop attendees. The cookies were a big hit.

During the workshop, I discussed the data formats available for Ajax responses. There’s XML and JSON, both of which can be parsed and then added to the document using DOM methods like createElement and appendChild. Another option is to simply send back HTML from the server and dump it into the document using innerHTML. If I ever find myself needing to update just one part of the page, this is the solution I use.

Suppose the part of the page I want to update is a div with an ID of “container”. I can just add the HTML that has been sent in the responseText property of XMLHttpRequest:

var container = document.getElementById("container");
container.innerHTML = xhr.responseText;

But innerHTML can cause some problems, particularly in Internet Explorer. If you use innerHTML to add or update form elements, all sorts of screwiness can occur. Sometimes the data from the newly added elements won’t be included when the form is submitted to the server.

Toby Cole—a Brighton-based developer working at Semantico—was at the workshop. He proposed an ingenious solution.

First of all, use the DOM to create a block level element—such as a div—using createElement. Then update the innerHTML property of this newly-created element. Finally, insert the updated element into the document using a DOM method like appendChild or insertBefore:

var newdiv = document.createElement("div");
newdiv.innerHTML = xhr.responseText;
var container = document.getElementById("container");
container.appendChild(newdiv);

Ta-da! The best of both worlds: the brevity and speed of innerHTML but without the problems in IE.

See, this is one of the reasons why I like the intimacy of workshops. It’s a great environment to exchange ideas. I think I’ve learned something new from the attendees at every workshop I’ve presented but this one was particularly fruitful.

Posted by Jeremy on Saturday, March 3rd, 2007 at 7:53pm

Comments

Jessica’s cookies rocked. :-)

The isolated innerHTML trick is a neat one. I thought I’d spotted something similar before, and I remember it now. It’s used in prototype as part of an escapeHTML function:

function escapeHTML(someText) {
  var div = document.createElement('div');
  var text = document.createTextNode(someText);
  div.appendChild(text);
  return div.innerHTML;
}

Which isn’t the same, but is also a neat trick to carry around in the toolbox.

# Posted by Dominic Mitchell on Saturday, March 3rd, 2007 at 8:13pm

This trick solve the problem with IE, but the methods innerText, innerHTML, etc, it’s not recommended by W3C:

http://www.webstandards.org/2006/04/13/dom-builder

Since they are proprietary methods from IE, other browsers just implement part of them, for example, innerText does not work in Firefox, you have to use innerContent. The right solution is to use createElement, appendChild, and others approved by W3C specification, the only problem is that using innerHTML is much more faster =(

# Posted by Carlos on Sunday, March 4th, 2007 at 1:54pm

Carlos, innerHTML may be proprietary but it is extremely well-supported in all browsers (I can’t speak for innerText, but I never even mentioned innerText). I share your misgivings about using any proprietary technology, but in the case of innerHTML, it really is a de-facto standard.

Also, I’m talking about using innerHTML in combination with XMLHttpRequest, which is also a proprietary technology. In for a penny, in for a pound.

The post you’ve linked to was written by me. At no point do I suggest that you shouldn’t use innerHTML, I simply said it’s "quick and easy but proprietary."

# Posted by Jeremy Keith on Sunday, March 4th, 2007 at 2:17pm

Hi Jeremy,

Sure, i see no problem in using a proprietary technology like innerHTML, XHR and others, in fact, i use both a lot =D, i had some problems using innerText, that’s why i mention it, my intention was to say "please readers take care when using proprietary methods, browsers can render it different on different versions…" ^_^, mostly when using proprietary technology =(

# Posted by Carlos on Sunday, March 4th, 2007 at 2:42pm

If you insert a script tag onto the page using innerHTML it won’t execute in any browser I’ve tested except IE Mac. However, if you use the above method the script will execute in Firefox.

Not exactly a useful discovery, but interesting none the less.

# Posted by Jake Archibald on Monday, March 5th, 2007 at 9:47am

Uh oh - you’re not stoking the flames of the innerHTML vs. DOM methods fire again, are you?! ;)

I have actually used the technique mentioned above before - except I used it to embed Flash, but the approach is the same.

# Posted by patrick on Wednesday, March 7th, 2007 at 4:56pm

Patrick, I have never stoked any fires so I don’t know what you mean by "again." If people have wilfully misread my posts in the past, that’s a problem for them, not me.

# Posted by Jeremy Keith on Wednesday, March 7th, 2007 at 5:04pm

I am afraid my sarcasm didn’t come across as planned. I know you didn’t stoke any fire - others stoked it for you by putting words in your mouth! I have read DOM Scripting and you clearly state that using innerHTML is useful for writing big chunks of HTML and is a vast improvement over the old school document.write technique. And, I have read your other articles and musings on the topic ; never once, that I recall anyway, have you banished anyone to hell for using it.

Next time I leave a little joke, I will try to make sure it’s actually funny.

I guess there a three things you should never talk about in mixed company: religion, politics and innerHTML.

# Posted by patrick on Wednesday, March 7th, 2007 at 5:50pm

This trick is also handy when inserting into tables. Prototype.js has a bit of code for that and I extended it for inserting into tables or any other element (except select) and run scripts too. In case anyone is interested…

http://dev.forkjavascript.org/trac/browser/trunk/public/javascripts/fork/mutate.js

# Posted by Peter Michaux on Thursday, March 8th, 2007 at 5:04am

I just ran into a situation where I needed to use innerHTML to fix IE’s dom module wierdness. This is part of a specialized drag and drop to manage a table. I attempted to build it cross browser compatible from the start, and it seemed to be going fine until I created the code to actually render the row (since I am not just dragging around a div or image I have to do better than just moving the original element)

var table=document.createElement('table');
table.style.width='640';
var rowclone=rowToDrag.cloneNode(true);
table.appendChild(rowclone);

div.appendChild(table);

div.innerHTML=div.innerHTML; //added for IE

see that last line? Without it my div doesn’t display when it is added to the body in IE. Examining the innerHTML it looked like it was building a nice table, but it wouldn’t show. I replaced all that with just setting innerHTML to ‘TEST’ and it merrily dragged around the screen. In a fit of madness I set it to itself and now it works in both browsers. I hate to have code that makes me look like a lunatic although clearly my solution was inspired by the devil.

Anyone have an explanation for this?

# Posted by DLG on Tuesday, March 13th, 2007 at 6:34pm

DLG: What is rowTodrag? Where is your tbody element? tbody is needed in IE for smooth operation. you need "640px" when you set the style width property.

# Posted by Peter Michaux on Tuesday, March 13th, 2007 at 11:32pm

Going back to the original code snippets:

var container = document.getElementById("container"); container.innerHTML = xhr.responseText;

and

var newdiv = document.createElement("div"); newdiv.innerHTML = xhr.responseText; var container = document.getElementById("container"); container.appendChild(newdiv);

Forgive me if I’m being ignorant here, but don’t those two do slightly different things. Especially if, say, I started out with a div that looked like this:

<div id="container">foo</div>

# Posted by Scott Johnson on Thursday, March 15th, 2007 at 2:20pm

Argh! The comment system just ate all of my formatting. What’s the proper procedure for inserting code blocks and lt/gt entities around here?

# Posted by Scott Johnson on Thursday, March 15th, 2007 at 2:22pm

I’ve had problems in some browsers refilling select menus and tables with innerHTML and AHAH - in Opera for instance, the new html, if inserted into certain elements, is interpreted as arbitrary XML. But if you replace the whole select element (for example), instead of just the options, then it seems to be ok.

# Posted by Keith Alexander on Sunday, March 18th, 2007 at 1:05pm

I’ve always preached to my developers to avoid using innerHTML. The reason is simple: it violates the separation between design and logic. I know that you’re most often using this to update small areas of the screen, but should you need to change the design, you need to get developers and designers involved for what should be a simple task. If you’re a one-(wo)man team, you still need to go through updates in (likely) two places. There are times when using innerHTML makes sense, but not when it involves back-end communication with the front-end. :)

# Posted by Ryan on Tuesday, March 20th, 2007 at 1:47am

Sorry. Comments are closed.

March 2007
SunMonTueWedThuFriSat
    123
45678910
11121314151617
18192021222324
25262728293031

Recommended Reading

XML Subscribe

Grab the RSS feed for this blog.

JavaScript API

Grab the RSS feed of comments for this entry.