IE’s innerHTML Method with SCRIPT and STYLE Tags

Introduction
A few months ago, I had a (common) situation where something worked in FF but not in IE. I was setting the innerHTML of a DIV with a string of HTML that had a STYLE tag close to the beginning. For some reason, when IE did its conversion from the string to DOM nodes that STYLE tag was being ignored. It took me a while to figure out why since this isn’t something very well documented outside of advanced Javascript books.

In this blog, I’ll describe under what circumstances cause IE to ignore SCRIPT and STYLE tags when setting innerHTML, and two solutions I’ve found to be effective in both IE and FF.

Problem Setup
Lets say that you have a DIV whose ID is “some-div.” You also have a string of HTML called someHTML that you want to use as the innerHTML to some-div. The traditional way of doing this is:


var someHTML = "<UL><LI>List item</LI></UL><BR><SPAN>span</SPAN>";
document.getElementById("some-div").innerHTML = someHTML;

This works fine until you start adding in SCRIPT and STYLE tags to someHTML:


someHTML = "<STYLE>DIV { color: red; }</STYLE><DIV>some text</DIV>";
document.getElementById("some-div").innerHTML = someHTML;

If you run that in FF, you'll see "some text" turn red; however, if you run that in IE, the color won't change.

One of my initial thoughts was that IE must be ignoring it simply because it was the first tag in the string. Even when I added other tags in front of it, IE still refused to change the text's color:


someHTML = "<SPAN></SPAN><STYLE>DIV { color: red; }</STYLE><DIV>some text</DIV>"; // Doesn't work
someHTML = "<DIV></DIV><STYLE>DIV { color: red; }</STYLE><DIV>some text</DIV>"; // Doesn't work

Since neither worked, I did some testing to see if IE would simply strip STYLE tags when you're setting innerHTML. This isn't the case as demonstrated by the following example:


someHTML = "<STYLE>DIV.my-div { color: red; }</STYLE>
<DIV class='my-div'>My Div</DIV><STYLE>DIV { color: blue; }</STYLE><DIV>Your Div</DIV>";

If you run that code in IE, both the text in both DIVs will be blue. If you run that code in FF, the text in my-div will be red and the text in the other will be blue, which is the correct result.

Formalized Problem
When IE converts a string of HTML into a DOM structure, it treats SCRIPT and STYLE differently than any other tags. When it hits one, it checks to see if there are any nodes before it that are "visible." (Visible very loosely means nodes that will be displayed when the structure is rendered.) If there aren't any visible nodes before it hits SCRIPT or STYLE, it simply tosses those away and continues processing.

Workarounds/Solutions
The reason IE wasn't rendering the STYLEs in the different someHTMLs earlier was because there were no "visible" nodes before the tags. This makes sense when there are no tags before the STYLE, but it is a little confusing in the examples where I had DIV and SPAN tags before it. Because there was no content in either, IE stripped them out as not being "visible." This, however, can be incorrect if they were specified like "<DIV style='width: 100px; height: 100px; border: 1px solid black;'></DIV>" in which case they would be as visible as you can get.

The real key to getting this to work in IE is to make sure you always have "visible" nodes before your SCRIPT or STYLE tags. I have found two ways of doing this: prefix "_" in front of your HTML string, or prefix a DIV whose style is "display: none;" and has "&nbsp;" as its body.

I opt for the first approach because it is more efficient. The first takes less time for IE to convert to a DOM node since it only has to create one new node rather than a parent/child pair for the DIV. There is a slight overhead of having to call removeChild to remove the "_" from the container DIV. This is also a problem with the second approach unless you want unnecessary DOM nodes laying around in memory.

Since the second approach creates less DOM nodes and you're going to have to call removeChild anyway, it is the more optimal solution. Here is a function that abstracts this process:


function setInnerHTML(inDOMNode, inHTML) {
     inDOMNode.innerHTML = "_" + inHTML;
     inDOMNode.removeChild(inDOMNode.firstChild);
}

Although I did not give a test case here for show that IE treats SCRIPT the same way it treats STYLE, you can try it yourself by doing "<SCRIPT>alert('HERE');</SCRIPT>" and see if IE shows the alert.

Conclusion
This is a problem that is not well documented nor well known unless you've read a book on advanced Javascript topics. If you're ever in a situation where you need to set the innerHTML of a DOM node that may contain SCRIPT or STYLE, you can use setInnerHTML to give you the correct results in all browsers.

About these ads
This entry was posted in Browsers and tagged , , , , . Bookmark the permalink.

7 Responses to IE’s innerHTML Method with SCRIPT and STYLE Tags

  1. Joel says:

    You’ve actually encountered a bigger issue with IE and .innerHTML

    The real bug(s) are described here:

    the Script tag suffers from this bug: http://webbugtrack.blogspot.com/2007/10/bug-142-appendchild-doesnt-work-on.html

    and the Style tag suffers from this one: http://webbugtrack.blogspot.com/2009/01/bug-143-createtextnode-doesnt-work-on.html

    which in reality are all issues with IE’s inconsistent handling of creating nodes, setting attributes, adding text and setting the innerHTML

  2. Zach Gardner says:

    Those are both other interesting bugs, but they are slightly different than what this post deals with. After further reading, I found out that SCRIPT, STYLE, and the comment <!– and –> are all considered “NoScope” elements by IE. NoScope means “no text in a textrun should point to it.” According to this post at MSDN (in the comments at the bottom), all NoScope elements are removed before it starts processing innerHTML or innerAdjacentHTML unless they are preceeded by at least one scoped element.

    Both of those bugs you posted are interesting as well, but I believe are slightly different than this NoScope issue with innerHTML. We can, however, agree that IE treats things inconsistently and often times against standards.

  3. Pingback: Using innerHTML to Update a SELECT – Differences between IE and FF | AllofE Technical Blog

  4. tarence says:

    Zach…Thanks a lot for this piece of information. Have been beating my head against the wall wondering why my first tag wasn’t being alerted. Made my day!

  5. casper says:

    Same here, big thanks for your idea, saved me a lot of time, since I already have been searching everywhere how to workaround this problem all day long ;)

  6. jdb says:

    8 hours!!!!! that’s what I wasted before I read your blog! thanks so much!!

    Works like a charm!

  7. Zach Gardner says:

    Glad you were able to use the post. If you’re interested in our new blog (this one is no longer updated), you can check out

    http://technical.allofe.com/

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s