DOMContentLoaded Event for Browsers

Update: 2014 March 19 - domReady version II has been created that provides a streamlined domReady function.

Update: 2008 June 13 - DOMContentLoaded for Browsers, Part V has been created that provides a domReady function without the overhead of the Dean Edwards' events code. If you're a prototype user you should check out Prototype JavaScript framework: document.observe which in version 1.6.0 gives you a dom:loaded event. If you don't have 1.6.0 or above of prototype or don't like their solution, check out domready.js in DOMContentLoaded for Browsers, Part V.

Update: 2006 June 22 - DOMContentLoaded Event for Browsers, Part II has been created that doesn't require the ie_domload.js external JavaScript file. Please check it out.

After learning of the DOMContentLoaded event in Mozilla browsers I knew it had to be added for other browsers. I wanted to add behavior to pages after the DOM had loaded and before the onload event. Some pages have images that take a long time to load, a DOMContentLoaded event allows a developer to add behavior after the DOM has loaded but before images have loaded.

The onload event fires after all content on a page is loaded, including images and will not fire before all images have been loaded. Menus would not work on a page until all the images had loaded. In the past I added a script element just before the end body element which allowed me to add behavior to a page before the onload event.

<script type="text/javascript">init();</script>
</body>

As long as I didn't add DOM elements to the body there didn't seem to be any problems. This has worked for many years because I usually don't add DOM elements to the body, I add behavior. This works well for menus, tree structures and sIFR. The problem is that I couldn't add DOMContentLoaded events at will, I had to add them to my init() function. I had to know before I created a page and if I added a new function I had to add the call to it in the init function. What I needed was to be able to use addEvent to add DOMContentLoaded events.

Dean Edwards' blog entry The window.onload Problem - Solved! fixed the problem for IE but not for other browsers. I wanted it all.

I modified Dean Edwards' addEvent function that had been modified by Tino Zijdel and combined it with James Edwards' domFunction to implement DOMContentLoaded functionality in browsers other than Mozilla and IE. I used the defer attribute to add a script for IE that runs when the DOM has loaded.

A function and array was added as described in a comment by Ian Darke, I only changed the name of the function and array.

// Array of DOMContentLoaded event handlers.
window.onDOMLoadEvents = new Array();

// Function that adds DOMContentLoaded listeners to the array.
function addDOMLoadEvent(listener) {
	window.onDOMLoadEvents[window.onDOMLoadEvents.length]=listener;
}

The beginning of the addEvent function was modified to call the addDOMLoadEvent function for DOMContentLoaded events.

	// DOMContentLoaded for all browsers.
	if (type == "DOMContentLoaded" || type == "domload")
	{
		addDOMLoadEvent(handler);
		return;
	}

A DOMContentLoadedInit function was created to process the array of DOMContentLoaded functions.

// Function to process the DOMContentLoaded events array.
function DOMContentLoadedInit() {
	// quit if this function has already been called
	if (arguments.callee.done) return;

	// flag this function so we don't do the same thing twice
	arguments.callee.done = true;

	// iterates through array of registered functions 
	for (var i=0; i<window.onDOMLoadEvents.length; i++) {
		var func = window.onDOMLoadEvents[i];
		func();
	}
}

Finally the browser had to be told to run the DOMContentLoadedInit function with extra checks for Safari and Opera 8.51 as described in a comment by Phil Green.

// If Mozilla, use the built in DOMContentLoaded event.
if(document.addEventListener && !window.opera &&
  !(!document.all && document.childNodes && !navigator.taintEnabled)) {
	document.addEventListener("DOMContentLoaded", DOMContentLoadedInit, false);
} else {
	// Add it to the brothercake domFunction() interval function.
	var funcDOMContentLoadedInit = new domFunction(DOMContentLoadedInit);
	// Just in case window.onload happens first, add it there too.
	addEvent(window, "load", DOMContentLoadedInit);
}

If the browser is Mozilla the built in DOMContentLoaded event is used, if IE, the defer attribute of the external ie_domload.js script emulates the Mozilla DOMContentLoaded event. All other browsers use a combination of domFunction and the window onload event, which ever one comes first. In the DOMContentLoadedInit function there is a check to see if it has already be called.

	// quit if this function has already been called
	if (arguments.callee.done) return;

If DOMContentLoadedInit has been called it exits.

To use the DOMContentLoaded event, add the following to the head section of your web page.

<script type="text/javascript" src="events.js"></script>
<!--[if IE]><script defer type="text/javascript" src="ie_domload.js"></script><![endif]-->

In your script make a call to addEvent.

addEvent(window, 'DOMContentLoaded', myFunction);

The object variable is ignored for DOMContentLoaded events, the window object is used in all cases. It does not work on Netscape 6.2 and the image does not load on IE 5.2 Mac though the events load as expected. It has been tested successfully on a variety of browsers, you can see the browsercam results at DOMContentLoaded.

You can find the source files at:

15 Comments

Gravatar Image1. Posted at 5/13/2006 9:56:02 AM by Steffen Rusitschka

Very nice script. Works like charm on my site (www.ruzee.com). Most of the time. I sporadically experience problems with Safari browsers. I'm using your lib to draw rounded, shadowed borders - heavily. Sometimes not all DIVs are drawn in Safari - as if the DOM is not yet completely loaded. Anyone else reported problems? But besides that - your script speed up my page by magnitudes! Thanks alot!

Gravatar Image2. Posted at 7/28/2006 12:31:10 AM by REM

There is a small good update to Deans addevent.

Gravatar Image3. Posted at 7/28/2006 2:16:42 PM by Tanny O'Haley

@REM, Thank you for the heads up. I have integrated Dean's changes into my script and it's been tested.

Gravatar Image4. Posted at 7/30/2006 7:49:50 AM by Diego Perini

Tanny,

I remember you where also searching hard for something like this for IE...

The property is usable on MS browsers 5 and over (also present in IE4):

document.activeElement

The event related to that property is "onactivate" or if that is not enough "onbeforeactivate"...

Read more on Dean blog, including links to MS documentation and Mozilla adoption of this standard.

If you have test cases that still doesn't work with these solutions send them, I will have a look...I have other fallbacks like "document.fileSize" for IE that is giving very good results.

For older browser Firefox < 1.5, Mozilla and Opera < 9 the only fallback is my current "DOMComplete" which compares

the TAIL of the file and what it find in the DOM for a match. Actually is very reliable and fires before images are loaded however it can be still improve.

I have recently update my "DOMComplete"

on my test site for these less capable browsers.

Hope applications and everybody writing for that may benefit from these findings...

Diego

Gravatar Image5. Posted at 8/2/2006 5:14:35 PM by António Cruz

Hi,

I would like to know if a dynamic script tag I created has already been loaded so I can access its javascript content without getting an error.

My current problem is only with Safari because I'm not succeeding in creating the load event for the dynamic script element in any way for this browser.

I know this discussion has been focused on document.onload but as subjects are related masybe anyone can (please!) help me on this?

Thank you very much,

António Cruz

Gravatar Image6. Posted at 4/1/2008 1:04:04 PM by Jen

Hello , is it possible to have a live example of this script ?

Gravatar Image7. Posted at 4/3/2008 11:10:03 AM by Tanny O'Haley

Hi Jen,

The Tabbed Interface uses the DOMContentLoaded event to run the tab.init() method. The sample in Date Input and Calendar Popup Instructions uses the DOMContentLoaded event to add click events to the day mask check boxes and if you haven't added the events adds date parse functionality to input elements with a "dateparse" class.

At work I use DOMContentLoaded to add a names field lookup that is similar to Google suggest, the date parser with a custom calendar button that goes in the text field, textarea auto expanding behavior, my form validation routines, ...

Tanny O'Haley

Gravatar Image8. Posted at 7/15/2008 8:41:16 PM by Carlos A. Pérez M.

I'm testing your ondomload and I get a message in IExplorer Stack overflow at line 0.

Is there a limit as to how many events can be added to the onload.

I have a test site but as it requires passwords etc I don't post them here if you answer back (by your email) I'll send it to you so you can test.

By the way, it works perfectly in Firefox

Gravatar Image9. Posted at 7/16/2008 7:44:01 PM by Carlos A. Pérez M.

I made a special link so that you can test the problem it's at this ulr

The corresponding lines of the parts where domload are included are surrounded by a lot of comments.

Gravatar Image11. Posted at 7/17/2008 9:34:20 AM by Tanny O'Haley

Hi Carlos,

I took a look at the link you provided and I have a couple of suggestions.

Move the script element for DomInit.js to the top. Make sure that it is the first script element on the page.

Delete the script element for DomIexplorer.js as it's functionality is already in your DomInit.js file.

You have an addLoadEvent() function that overwrites window.onload. Get rid of the addLoadEvent() function and replace calls to the addLoadEvent() function with addEvent(window, "load", func) or change your addLoadEvent() function to use addEvent(). That is of course if you really want to use the load event instead of the DOMContentLoaded event.

Think about using web standards in writing your HTML code. It is much easier to debug than nested tables. There are techniques to use that don't use tables to accomplish the same effect.

Check out the latest entry on DOMContentLoaded.

Gravatar Image12. Posted at 7/17/2008 8:26:02 PM by Carlos A. Pérez M.

I just created another test with your suggestion DomContentLoaded and it does work fine on the event loading BUT, there is always a but, sometimes I get an unspecified error on line 71 and on line 149 (which really are 70 and 148).

You'll see that Im doing the clock and title events with domReady.

As always this occurs only en IExplorer not in Firefox the new test is located at: http:{ Link }

Thanks again for your quick response.

Gravatar Image13. Posted at 7/17/2008 9:27:25 PM by Tanny O'Haley

Hi Carlos,

Alas, I no longer have IE6 to use for testing pages. I did test the page in IE7 and did not experience any problems, though it did take a very long time to download the page. I tried clicking from the link, opening a new browser window and pasting the link and finally pressing the Enter key in the address bar.

The page is a blog entry that has updated links at the top. I need to find a way to be more specific. The page is left for historical and linking purposes. The reason I told you to delete the script element in point two is because it has been deprecated by a newer methodology in the one file. Two files are no longer needed.

I wish I could help you with my code, but my work and family now take most of my time. You might want to check out the 456 Berea Street Bookstore.

Gravatar Image14. Posted at 9/20/2010 3:53:26 AM by Rana Bhavna

I would like to know if SWFObject could be configured to do its thing (executing the createSWF() method) before the Web browser has fired its 'DOM loaded' event. That way, my Flash files would not have to wait until the JavaScript for the ads have been loaded before they can be displayed by SWFObject.

Gravatar Image15. Posted at 9/21/2010 1:03:02 PM by Tanny O'Haley

It depends on how you're implementing the createSWF() method. You'll have to look at the documentation, but I believe the SWFObject has it's own DOMReady detection which is the same as DOMContentLoaded.

Add a comment

Discussion for this entry is now closed.