Dynamic SCRIPT and STYLE elements in IE

January 26th, 2007. Tagged: browsers, firefox, IE, JavaScript

So you know how to add external scripts and styles, using the DOM, after the page is loaded. And what if you don't have external files, but have some style definitions and some JS code as text and you want it inserted and executed into a page.

The DOM way

"Ha! An easy one", you'd say and then go like:

var ss = document.createElement('script');
var scr = 'alert("bah");';
var tt = document.createTextNode(scr);
ss.appendChild(tt);
var hh = document.getElementsByTagName('head')[0];
hh.appendChild(ss);

"Ha!" in turn says IE, "No way!"

The IE way for SCRIPT

The above won't work in IE, but you can use the text property instead of creating a text node. Interestingly enough, this also works in Firefox.

var ss = document.createElement('script');
var scr = 'alert("bah");';
ss.text = scr;
var hh = document.getElementsByTagName('head')[0];
hh.appendChild(ss);

The IE way for STYLE

STYLE, SCRIPT, what's the difference, they are merely elements of the DOM tree. For the normal browsers, yes, so creating a text node with the stylesheet body will work in Firefox. For IE, you need a workaround.

var ss1 = document.createElement('style');
var def = 'body {color: red;}';
ss1.setAttribute("type", "text/css");
ss1.styleSheet.cssText = def;
var hh1 = document.getElementsByTagName('head')[0];
hh1.appendChild(ss1);

Note that while in the SCRIPT case I took the liberty of skipping the type attribute, it's absolutely required here.

So with a bit of object sniffing, we can get a cross-browser solution:

var ss1 = document.createElement('style');
var def = 'body {color: red;}';
ss1.setAttribute("type", "text/css");
var hh1 = document.getElementsByTagName('head')[0];
hh1.appendChild(ss1);
if (ss1.styleSheet) {   // IE
    ss1.styleSheet.cssText = def;
} else {                // the world
    var tt1 = document.createTextNode(def);
    ss1.appendChild(tt1);
}

Update: note that it's important for IE that you append the style to the head *before* setting its content. Otherwise IE678 will *crash* is the css string contains an @import. Go figure!

Tell your friends about this post: Facebook, Twitter, Google+

62 Responses

  1. [...] Dynamic SCRIPT and STYLE elements in IE – Going conditional on the text attribute For IE you can use the text property instead of creating a text node. Creating a text node with the stylesheet body will work in Firefox. For IE, the type attribute, it’s absolutely required here. So with a bit of object sniffing, we get a x-browser solut (tags: DOM JavaScript) [...]

  2. Thank you so much!!
    I’ve tried to solve this problem for so long, trying to find the way to dynamically add script and style tags during the ajax-application work.
    Now it works in IE too.

  3. hey ash,

    For me IE is having some problem. how did you solve your problem. please share your idea with me

    Thanks

  4. Unbelievable, this helped me so much :) Thank you guys!!!!!!!!

  5. I have a calendar field. which is having one text field and one calendar icon. with this i have a attached with the image. Text field id and icon id is attached in the script variables.

    So if you click the image, DHTML caledar box will be opened.

    Now let me come to the real problem. i have plus icon. if i click the plus icon i need to add one more set of calendar.

    I am adding this new calendar through javascript. In Firefox this is working. but in IE this is not working. new calendar is coming but if i click the icon, DHTML calendar popup is not loaded.

    can any one solve my problem.

  6. [...] I looked up a few ways to include a <style> element, but realized there’s an easier way; I split the style into its own stylesheet and added a line to Javascript: $(‘head’).append(‘<link type=”text/css” href=”/css/kb.css” rel=”stylesheet” >’); before the $(‘<div id=”keyboard-holder”>’).insertAfter(‘#q’).load(‘/inc/keyboard.html’); // load via Ajax and now the style loads dynamically and easily. Luckily, jQuery handles identifying and executing <script> elements in Ajax’ed code, so I don’t have to pull that out. [...]

  7. Thanks a whole lot, this help me immensely. I dynamically insert a javascript function into web page using greasemonkey and have spent three days trying to port it to IE and Reify’s Turnabout until I found this. Thanks again.

  8. Your IE Style trick really helped me out, I was getting desperate after trying every other standard/non-standard way! Just a quick note, script.text is actually standard http://www.w3.org/TR/2003/REC-DOM-Level-2-HTML-20030109/html.html#ID-81598695 and works in Safari & Opera as well. It is nice not to have to fork the code on IE for scripts at least…

  9. Great tip, thanks! I was hitting a wall here trying to get this to work on IE. Very cool!

  10. to include other browsers (firefox):

    var ss1 = document.createElement(‘style’);
    var def= ‘#Browse .productLabel{display:none;}’;
    ss1.setAttribute(“type”,”text/css”);
    if(ss1.styleSheet){
    ss1.styleSheet.cssText = def;
    var hh1 = document.getElementsByTagName(‘head’)[0];
    hh1.appendChild(ss1);
    }
    else
    {
    ss1.innerHTML = def;
    document.getElementsByTagName(‘head’)[0].appendChild(ss1);
    }

  11. Thanks for the tip.

    Silly IE 6 & 7 crash each time an import directive is part of the cssText. IE makes me code angry. :/

    Extra credit goes to the person who can work around IE crashing at the following statement (without turning it into a LINK element)

    ss1.styleSheet.cssText = ‘@import url(“external.css”);’;

    Anyone.

  12. ss1.styleSheet.addImport(“external.css”);

    Just make sure to do this after manipulating cssText. Manipulating cssText after addImport causes the import to be overwritten.

  13. Good find, thanks for sharing, Matt!

    S

  14. Thanks for taking the time to blog this :-)

  15. Awesome post. I’ve spent days adn thenh days more trying to get IE to parse and apply am on the fly dhtml css script. I’ve hacked and searched to 2 years (not continually,mind you), but the “styleSheet.cssText” was the missing piece I couldn’t find. Thanks, again, this completely rocks.

    As a way of saying thanks, here is an cross domain AJAX call , and can be asynchronous or synchronous:

    function _ImportScript(jsurl, bUseCache, CallBackFunc, SafariTest )
    {
    //Supply CallBack to verify load before accessing loaded objects.
    //Use SafariTest to trigger the callback func for safari, e.g. test for vars defined in the loaded script
    var head = document.getElementsByTagName(‘head’).item(0);
    var s = document.createElement(“SCRIPT”);
    s.src = ((bUseCache)?jsurl:GetUniqueURL(jsurl));
    s.type = “text/javascript”;
    if(typeof CallBackFunc == “function”){
    if(typeof s.onreadystatechange != “undefined”){//ie
    s.onreadystatechange = function(){if(/loaded|complete/.test(s.readyState)){s.onreadystatechange = null; CallBackFunc();} };
    }else if(/safari/i.test(navigator.userAgent) && SafariTest ){ //Safari does not support event callbacks
    window.SafariLoaded = function(){if(eval(SafariTest)){ CallBackFunc(); }else{ window.setTimeout(“window.SafariLoaded()”,100)}; }
    window.SafariLoaded();
    }else{
    CallBackFunc.once = true;//avoid repeated callbacks
    addEvent( s, “load”, function(){ if(CallBackFunc.once){CallBackFunc.once = false; CallBackFunc();} } ); //mac:camino,moz,fx. win:moz,fx,opera 9x
    addEvent(window, “load”, function(){ if(CallBackFunc.once){CallBackFunc.once = false; CallBackFunc();} } ); //opera 8x
    }
    }
    head.appendChild(s);
    }

  16. I made a variation that will take information added to a DIV via ajax, and then turn it into usable functions

    function setAndExecute(divId) {
    var div = document.getElementById(divId);
    var x = div.getElementsByTagName(“script”);
    var ss = document.createElement(‘script’);
    for( var i=0; i < x.length; i++) {
    //alert(x[i].text);
    ss.text = x[i].text;
    hh = document.getElementsByTagName(‘head’)[0];
    hh.appendChild(ss)
    }
    }

  17. Here’s what worked for me (for both IE and Firefox):

    var lnk = document.createElement(‘link’);
    lnk.rel=’stylesheet’;
    lnk.type=’text/css’;
    lnk.href=’name_of_css_file’);
    document.getElementsByTagName(‘head’)[0].appendChild(lnk);

  18. Yep, Sigalit Ur, your way (DOM inclusion) works when you have an external stylesheet.

    The problem I was solving in the post was a little different – when you don’t have an external stylesheet, but you have a bunch of style definitions and you want to inline them.

    Best,
    Stoyan

  19. On IE it seams to be a problem with pseudo-class. They are not applied. Can anyone give me a solution?

    Here is an example:

    function addStyles(styles) {
    var head = document.getElementsByTagName(‘head’)[0];
    var style = document.createElement(‘style’);
    style.type = ‘text/css’;

    if (style.styleSheet) { // IE
    style.styleSheet.cssText = styles;
    } else { // others
    var tt1 = document.createTextNode(styles);
    style.appendChild(tt1);
    }

    head.appendChild(style);
    }

    addStyles(‘.una tr:first-child > td { border-top: none; } .una { border-bottom: 1px solid #BEBEBE; } .una td { border-top: 1px solid #BEBEBE; border-bottom: 1px solid Red; }’);

    12
    12
    12

    The css rule ‘.una tr:first-child > td’ is not applied.

    Thx

  20. This is the html code:

    <!DOCTYPE HTML PUBLIC “-//W3C//DTD HTML 4.01 Transitional//EN” “http://www.w3.org/TR/html4/loose.dtd”>
    <html>
    <head>
    </head>

    <body>

    <script>
    function addStyles(styles) {
    var head = document.getElementsByTagName(‘head’)[0];
    var style = document.createElement(‘style’);
    style.type = ‘text/css’;

    if (style.styleSheet) { // IE
    style.styleSheet.cssText = styles;
    } else { // others
    var tt1 = document.createTextNode(styles);
    style.appendChild(tt1);
    }

    head.appendChild(style);
    }

    addStyles(‘.una tr:first-child > td { border-top: none; } .una { border-bottom: 1px solid #BEBEBE; } .una td { border-top: 1px solid #BEBEBE; border-bottom: 1px solid Red; }’);
    </script>
    <table border=0 width=100% class=”una” cellspacing=”0″ cellpadding=”0″>
    <tr><td>1<td><td>2<td></tr>
    <tr><td>1<td><td>2<td></tr>
    <tr><td>1<td><td>2<td></tr>
    <table>
    </body>

    </html>

  21. I found a solutin to readd the rules:

    if (style.styleSheet) { // IE
    var css = document.styleSheets['calculeStyles'];
    for(var i = css.rules.length; i > 0; i–)
    {

    changeCssRule(css, css.rules[0].selectorText, css.rules[0].style.cssText);
    css.removeRule(0);
    }
    }

    but …

  22. Thankssssssssssssssssss GOD!!!!!!

    I was struck in this problem since last week and this SUCKY DAMN IE was not letting me create text node inside of script tab. I really appreciate your help. God Bless you.

    A’meen

  23. Marian,

    Try moving the head.appendchild up, it worked for me in ie7:

    function addStyles(styles) {
    var head = document.getElementsByTagName(’head’)[0];
    var style = document.createElement(’style’);
    style.type = ‘text/css’;

    head.appendChild(style);
    }

    if (style.styleSheet) { // IE
    style.styleSheet.cssText = styles;
    } else { // others
    var tt1 = document.createTextNode(styles);
    style.appendChild(tt1);
    }

  24. great post, thanks for your help :)

  25. Is this method is cross-browser? What about Safari?

  26. Thanks for this.

    Following simple function can be used for cross browser support:

    function agent(v) { return(Math.max(navigator.userAgent.toLowerCase().indexOf(v),0)); }

    if (agent(‘msie’)) { // IE
    I hate IE 6
    } else {
    rest of the world
    }

  27. [...] The problem I found is when you set styles dynamically. Say you have a bunch of CSS content as a string and you want to create a new style tag and shove the code there. I’ve blogged about this before. [...]

  28. Thanks a lot! The only page where I found the solution for loading dynamically style and script in IE7!

  29. Thanks Fernando, glad it helped :)

  30. Thank you! Really helped a lot.

  31. Thanks this is so neat. Now i can clean the dust from IE and maby start using it. It’s strange because it was posted in 2007. Now there is IE 7, but that doesn’t make a big difference
    PS from your email i can see that you are from my country-Bulgaria.

  32. By the way, appending the text node to the parent before appending the parent to the document creates a memory leak (at least in IE): a temporary document context is created to hold the parent-child node structure, then never cleaned up after the parent is moved to the existing document. Always append a node to an in-document element, never to a floating one.

  33. A @font-face declaration going into ss1.styleSheet.cssText will crash IE6-8 really bad, FYI.

  34. really, Paul? That’s interesting, thanks for your comment

  35. filter: progid:DXImageTransform.Microsoft.gradient in script bellow not work in IE 7:
    table = document.createElement(‘table’);
    table.setAttribute(‘cellspacing’,’0′);
    table.setAttribute(‘cellpadding’,’2′);
    tbody = document.createElement(“tbody”);

    table.appendChild(tbody);
    tr = document.createElement(‘tr’);
    tr.setAttribute(‘valign’,'top’);

    tr.style.cssText= “filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=” #B554FF”, endColorstr=” #B554BB”)”;
    tbody.appendChild(tr);

    Could you help to solve the issue above?
    Many thanks,
    Pao,

  36. @Pao, I think startColorstr and endColorstr expect RGBA values

    try startColorstr=”#B554FFFF”, endColorstr=”#B554BBFF” (two extra FFs)

  37. “A @font-face declaration going into ss1.styleSheet.cssText will crash IE6-8 really bad, FYI.”

    Is there a workaround for this? I NEED to be able to dynamically insert “@font-face” declarations in IE. Thanks in advance!

  38. [...] In IE6-8, using createStyleSheet and then setting styleElem.styleSheet.cssText to a text value that includes a @font-face declaration going into will crash IE6-8. (src) [...]

  39. [...] jQuery method that would load the CSS dynamically. So I wrote something that is heavily based on a post by Stoyan [...]

  40. [...] qui [...]

  41. [...] inner DOM element text. Well, there are small differences between IE and the other browsers, but the solution is working for [...]

  42. Hi Guys!!

    i’ve a problem with dynamically load script in IE:

    var headID = document.getElementsByTagName(“head”)[0];
    var script = document.createElement(‘script’);
    script.type=’text/javascript’;
    script.src=”js/ordini/ImmOrd.js”;
    script.setAttribute(“onload”, “crtGridRicProd();”);
    headID.appendChild(script);

    could you help me??
    thanks!

  43. saved me a ton of time…thank you for this !!!!

  44. Millions and Millions of time saver :)
    I’s struggling for the IE specific code.
    Thanks!

  45. I find that you can only change the .text attribute once with FF then it stops working. Any ideas?

  46. [...] Fortunately Uncle Google already had a solution. Stoyan Stefanov posted at his blog a solution for this problem and also a way to insert script tag dynamically. His post can be found here: http://www.phpied.com/dynamic-script-and-style-elements-in-ie/. [...]

  47. free money…

    [...]Dynamic SCRIPT and STYLE elements in IE / Stoyan’s phpied.com[...]…

  48. Great piece of code. This has helped me as well as many others i can see.

  49. playstation 3 streaming…

    [...]Dynamic SCRIPT and STYLE elements in IE / Stoyan’s phpied.com[...]…

  50. hello.

    I has been solved my problem.
    thank you!

  51. Thank you so much!!!!
    .
    Really, you got my problem solved!!!
    I dont even remember how long i have been searching for it’s fix!!!
    I’ve tried to solve this problem for so long, trying to find the way to dynamically add script and style tags during the ajax-application work.
    Now it works in IE too.

  52. Thanks!
    Thanks!
    Thanks!

  53. Hi,
    Thanks for this article, and especially the comments of Marian. His solutions makes cross-browser.

  54. [...] with reference to this site Dynamic SCRIPT and STYLE elements in IE [...]

  55. thx thx thx!!!

  56. Awesome..saved my day..

    thanks a lot

  57. HI, I am creating each time when I select drop down items in select. Its creating more then 31 styles in But IE allows only 31 in head. So please help me how I can remove existing before adding new tag

  58. HI, I am adding new in HEAD dynamically when I select drop down options in . Its creating more then 31 styles in But IE allows only 31 tags in . So please help me how I can remove existing before adding new tag

  59. HI, I am adding new style tag in HEAD dynamically when I select drop down options in select tag. Its creating more then 31 styles in head tag. But IE allows only 31 style tags in head . So please help me how I can remove existing style tag before adding new style tag

  60. Wayy cool! Sоmme extremely valid points! I appreciate you writing
    this artіcle plus the rest of thee skte is also very goоd.

  61. It is perfect time to make some plans for the longer term annd it
    is time to be happy. I’ve read this post and if
    I may just I wish to recommend you some interesting things or tips.
    Maybe you could write subsequent articles regarding this article.
    I want to read more things about it!

  62. Quality content is the secret to be a focus forr the users
    to pay a quick visit the web site, that’s what this wweb page is
    providing.

Leave a Reply