The Curious Case of document.write

document.write is weird. It inserts HTML into the page wherever it appears. Well, it inserts its HTML directly after the script tag it appears in. Only if you run it before the document has been loaded. After? It clears the page and inserts just its content.

It can insert content which will explicitly break the rest of the page:

document.write('<plaintext>')

Or play a fun game of Russian Roulette:

if (Math.random() > 0.9)
  document.write('<!--')

It turns out, the idea that it inserts it’s output directly after the script tag it’s contained in is important.

For example:

<script>
  document.write('<script src="jquery.js"></' + 'script>');
  alert(jQuery.guid)
</script>

will error, reporting that jQuery is not defined.

<script>
  document.write('<script src="jquery.js"></' + 'script>');
</script>
<script>
  alert(jQuery.guid)
</script>

on the other hand will execute just fine, as the second script tag won’t execute until the injected script tag is finished.

It only gets weirder from there. Let’s consider:

<script>
  console.log('a');
  document.write('<script src="printC.js"></' + 'script>');
  console.log('b');
</script>
<script>
  console.log('d');
</script>

Where printC.js contains:

console.log('c')

This file will log:

a
b
c
d

Meaning the remainder of the first script tag finished executing passing over document.write, but the second script tag was blocked until printC.js had a chance to run.

It’s valuable to remember that this method of inserting content really only makes sense when the page is first being parsed. What happens if you try to document.write after the page has loaded? The logical thing would be for it to error or do nothing. What it actually does is clear the page and replace its content with what you wrote:

setTimeout(function(){
  document.write("Oops");
})

Is there ever a good use for document.write?

None that I’m aware of. Ad providers seem to like it as it allows them to switch to loading a tracking image rather than making an AJAX request if the user is using Netscape 2. In the modern world, there’s not much use for it.

You can still find all sorts of great tools which will inexplicably take your HTML and wrap it in document.write calls though.

Can you document.write inside document.write?

Yes!

Like, forever?

No, 20 times.

Seriously? 20?

Yes.

Chrome is without a doubt a better browser, it supports 21.

Did they both independently come up with that?

Firefox fixed the potential crash bug first, and Webkit copied their solution. IE is described as having a similarly arbitrary, if lower, limit.

How could I make the browser crash before that:

<div id="uniqid">
  <script language="JavaScript" type="text/JavaScript">
    document.write("&gt;"+document.getElementById('uniqid').innerHTML+"&lt;");
  </script>
</div>

(from the ticket)

What sort of dumb things can I do with document.write?

All sorts!

You can load a synchronous AJAX request and insert it into the page:

x = new XMLHttpRequest()
x.open('GET', "", false)
x.send()
document.write(x.responseText);

The loading of the request will block the page load, and the content will be inserted as if it was a part of the original page. In this case we are inserting the page’s content itself (that’s what an empty URL means), which will in turn insert the page’s content again infinitely *.

  • By infinitely, we mean 20 times. Or 21. Or some lesser IE number.

You can do all sorts of fun things with that.

Anything else?

It’s not in the current spec (but was in older ones), but document.write can actually take multiple arguments. document.write('H', 'I').

If it’s useless, why am I reading about it?

That’s a great question!


Our next post in the ‘Web Stuff You Should Never Use’ series will be on the eight year drama-fest that was XHTML. Our next useful post will be on some nifty things you can do with Mutation Observers. Get notified of both by subscribing below.

Like this post? Share it with your followers.

Sign up to get our next post delivered to your inbox.

Follow us to get our latest updates.