Insert in place without document.write

    James Edwards

    So here’s the situation: you want to syndicate some content using JavaScript to pull in the data (like AdWords or similar programs). The syndication script can’t know anything about the page it’s being used on — so it can’t have a dependency on the existence of particular elements. Yet the host page needs to be able to control where the content is inserted — the syndication script needs to insert the content wherever the <script> tag is.

    How do you do it?

    Well you probably do what Google does and use document.write. But document.write is not a nice technique, it has some notable issues:

    • document.write does not work in XHTML mode (on XHTML pages served as XML)
    • content written in with document.write may not subsequently appear in the page’s DOM, which means no further access to manipulate it programmatically, and no access to accessibility APIs
    • document.write is conceptually wrong because it treats nodes as serialized text — which they’re not — they’re nodes

    But what’s the alternative? DOM creation techniques need an existing element reference to work with; even innerHTML needs to know where to write the HTML. And in both cases, simply appending to <body> is not an option if you want the new content to appear inline with the existing content.

    I was faced with this dilemma a few days ago, until an obvious solution dawned on me — we do in fact have a predictable refence: the <script> element itself!

    All we need is a way of identifying the including <script> in the DOM, and then we can use the insertBefore method to append new HTML directly before it.

    So, given a syndication script with a fixed ID:

    <script type="text/javascript" id="syndication" src="syndication.js"></script>

    We can go from oldskool nastiness like this:

    document.write('<p id="syndicated-content">Here is some syndicated content.</p>');

    To modern loveliness like this:

    var newcontent = document.createElement('p'); = 'syndicated-content';
    newcontent.appendChild(document.createTextNode('Here is some syndicated content.'));
    var scr = document.getElementById('syndication');
    scr.parentNode.insertBefore(newcontent, scr);

    We could even go a step further and remove the <script> ID, but in that case we would need a concrete method for identifying the specific element. We could do that by knowing its SRC:

    var scripts = document.getElementsByTagName('script');
    for(var i=0; i<scripts.length; i++)
        if(scripts[i].src == '')
            //scripts[i] is the one

    And there you have it – a simple but elegant way of inserting content in place, removing the last vestige of need for document.write!