zachleat’s Ugly Mug

Zach Leatherman

DOMContentLoaded Inconsistencies (in Browsers and JavaScript Libraries)

04 December 2008Read this in about 5 minutes.

Quick Summary

  • Prototype and Dojo are the only major JavaScript frameworks that correctly time the DOMContentLoaded inside of an iframe in Internet Explorer. MooTools comes close and both YUI and jQuery both exhibit incorrect behavior.
  • Usually, browsers that have a native DOMContentLoaded event will fire it after both JavaScript and CSS (external script, link tags) have loaded. But Opera fires prior to CSS link tags loading.

We all know the problem, but we may not all call it the same thing. Every popular JavaScript library has its own name for the DOMContentLoaded event.

JavaScript LibraryEvent Name
YUIDOMReady
jQueryready
MooToolsdomready
Prototypedom:loaded
DojoaddOnLoad

But the naming scheme isn’t the only part about this event that’s inconsistent. There are a few hacks strewn around the net that have been bastardized (read: modified to the will of library authors) into each individual framework. These have been posted time and time again, but for post completeness are the following:

IE DOMContentLoaded HackDescription
doScroll by Diego PeriniUses a doScroll method call, which will throw an error if the ondocumentready event hasn’t fired on the primary document (take note of the usage of the word primary). Once doScroll doesn’t throw an error, it is assumed the DOM has loaded.
onreadystatechange and readyStateonreadystatechange “fires when the state of the object has changed,” and changes the readyState property of the object through the following states (not all apply to every type of element): uninitialized, loading, loaded, interactive, and complete. (source: MSDN) Usually set on the document object, or a script element (as used in the Script Defer method described next.
Script Defer by Dean Edwardsdocument.write’s a script tag with a defer attribute. Defer will cause the browser to delay execution of the script until the DOM has successfully loaded (using onreadystatechange on the script tag until its readyState is “complete”). Without defer, the browser would execute any script tag immediately.
HTC Behavior by Dean EdwardsMuch less popular approach using proprietary HTC Behavior files. Generally avoided due to the addition of an extra HTTP request to the page in order to download the external .htc file. As a side note, if using this approach, the "oncontentready" event will work better than the “ondocumentready” event used by Mr. Edwards.
Ghetto MethodOf course, the easiest way to do it is to put a script tag right above your ending </body> tag that triggers the event manually. This really only works if you have full control of the content, and isn’t really a library solution. Worth noting though.

Benchmark for Library DOMContentLoaded Implementations

Benchmark for Library DOMContentLoaded Implementations

I created a benchmark trying to answer the simple question: when does the DOMContentLoaded event fire? Each implementation has different effects, especially in iframes and with stylesheets.

What Works

The Internet Explorer hacks presented above are reliable when used on a standalone document (not inside of an iframe).

Mozilla Firefox, Safari, Chrome, and Opera all contain a native DOMContentLoaded event that each framework uses to consistently fire at the correct time. So, it isn’t even worth summarizing the results for tests in every browser with a native DOMContentLoaded event, except Opera. Opera took a different design approach with their DOMContentLoaded event (certainly not wrong, just different), which we’ll analyze below.

Internet Explorer inside an Iframe

All libraries below did no branching based on IE versions, all used the same method for IE6, IE7, or IE8. I performed no tests in IE8, however.

JavaScript LibraryMethodWaited for:
<body> <script><head> <script><link> CSS<img>
YUI 2.6.0doScroll, setTimeoutIncorrect: Fires almost immediately (~20ms)
jQuery 1.2.6window onloadXXXX
Prototype 1.6.0.3Script DeferXXX
MooTools 1.2.1doScroll and set innerHTML, setTimeout*XX
Dojo 1.2.0Script DeferXXX
IEContentLoadeddoScroll, document.onreadystatechangeIncorrect: JavaScript error.
addDOMLoadEventScript DeferXXX
  • For some reason, not only did the MooTools library not wait for the body script to trigger DOMContentLoaded, the body script never executed at all.

The most important takeaway from this blog post are the successful methods of faking DOMContentLoaded in Internet Explorer. The obvious library winners here are Prototype and Dojo, with the addDOMLoadEvent script also exhibiting correct behavior. MooTools is a close runner up, and I would be interested to find out why it didn’t execute the body script (that’s left for another day, or perhaps a generous commenter).

Opera 9.6

JavaScript LibraryMethodWaited for:
<body> <script><head> <script><link> CSS<img>
YUI 2.6.0Native DOMContentLoadedXX
jQuery 1.2.6Native DOMContentLoaded + Code to wait for StylesheetsXXX
Prototype 1.6.0.3Native DOMContentLoadedXX
MooTools 1.2.1Native DOMContentLoadedXX
Dojo 1.2.0Native DOMContentLoadedXX
IEContentLoadedN/A to OperaXXX
addDOMLoadEventNative DOMContentLoadedXX

As you can see above, Opera typically will fire DOMContentLoaded prior to stylesheets loading successfully (ignoring the jQuery specific code to provide consistency cross-browser)

Thanks to Adam Koch for first pointing me in the direction of jQuery in an iframe ignoring DOMContentLoaded in IE.

Update: There is an open ticket for YUI on Sourceforge, and I’ve opened a ticket for jQuery on their Trac site.

Say hello on and GitHub.

Let my Feed sit idle in your RSS Reader.

Zach Leatherman is a Professional Front End Engineer. He loves building for the web and has been writing here since 2007.

He enjoys spending time with his beautiful wife Traci and their two Great Danes, Roxie and Ella. They also have a cat, a rabbit, goldfish, and usually one or more tarantulas. Read more »