JavaScript Document DOMContentLoaded Event

Beginner
⏱️ 12 min read
📚 Updated: Jul 2026
🎯 5 Examples
🚀 5 Try-it labs
Baseline
Document event

What You’ll Learn

The DOMContentLoaded event fires when the HTML document is fully parsed and deferred scripts have run. Learn how it differs from load, when to guard with document.readyState, why there is no onDOMContentLoaded property, and how to use it safely—with five examples and try-it labs.

01

Kind

Document event

02

Type

Event

03

Cancelable

No

04

Status

Baseline · Widely available

05

Handler prop

None (use addEventListener)

06

Waits for images?

No

Introduction

Most beginner bugs look like this: your script runs in <head>, calls document.getElementById(...), and gets null because the element is not in the DOM yet. DOMContentLoaded is the classic signal that says: the HTML tree is ready to query.

It does not mean every image finished downloading. For a fully loaded page (images, styles, and other sub-resources), use the window load event instead. MDN calls mixing those up a common mistake.

💡
Simple alternative

Often you can skip the listener entirely: put your script at the end of <body>, just before </body>. By then the DOM above the script already exists.

Understanding DOMContentLoaded

A standard Document event. Per MDN it fires when:

  • The HTML document has been completely parsed.
  • Deferred scripts (defer and type="module") have downloaded and executed.
  • It does not wait for images, subframes, or async scripts.
  • It does not wait for stylesheets by itself—but deferred scripts wait for stylesheets, and DOMContentLoaded is queued after those deferred scripts.
  • It is not cancelable.
  • There is no onDOMContentLoaded handler property.

⚖️ DOMContentLoaded vs load vs readyState

APIMeaningUse when
DOMContentLoadedHTML parsed; deferred scripts doneYou need to query/update the DOM ASAP
window loadFull page including images & sub-resourcesYou truly need everything finished
document.readyStateloading / interactive / completeGuard late/async scripts; related state machine
readystatechangeFires whenever readyState changesFine-grained loading timeline logging

📝 Syntax

Use the event name with addEventListener (MDN: there is no onDOMContentLoaded property):

JavaScript
addEventListener("DOMContentLoaded", (event) => { });

Event type

A generic Event.

Cancelable

No. This event is not cancelable.

Basic usage (MDN)

JavaScript
document.addEventListener("DOMContentLoaded", (event) => {
  console.log("DOM fully loaded and parsed");
});

⚠️ What If the Event Already Fired?

If your script runs with async, is injected later, or resumes after await, DOMContentLoaded may have already happened. A listener alone would never run. MDN’s safe pattern checks document.readyState first:

JavaScript
function doSomething() {
  console.info("DOM loaded");
}

if (document.readyState === "loading") {
  // Loading hasn't finished yet
  document.addEventListener("DOMContentLoaded", doSomething);
} else {
  // DOMContentLoaded has already fired
  doSomething();
}

There is no race between the if check and addEventListener: JavaScript runs to completion in the current turn, so the document cannot flip to “loaded” between those two lines.

⚡ Quick Reference

GoalCode / note
Listendocument.addEventListener("DOMContentLoaded", fn)
Handler propertyNone — no onDOMContentLoaded
Cancelable?No
Waits for images?No (use load for that)
Late / async scriptCheck readyState === "loading" first
Simple alternativePut script just before </body>
MDN statusBaseline · Widely available

🔍 At a Glance

Four facts to remember about DOMContentLoaded.

Event type
Event

Generic

Cancelable
no

Not cancelable

Images?
no wait

DOM only

Status
Baseline

Use freely

Examples Gallery

Examples follow MDN Document: DOMContentLoaded event and show the everyday patterns you will use in real pages.

📚 Getting Started

Register the listener and run DOM setup safely.

Example 1 — Basic addEventListener

MDN’s starter pattern: log when the DOM is fully loaded and parsed.

JavaScript
document.addEventListener("DOMContentLoaded", (event) => {
  console.log("DOM fully loaded and parsed");
  const title = document.querySelector("h1");
  console.log("Found h1:", title ? title.textContent : "(none)");
});
Try It Yourself

How It Works

The browser finishes parsing the HTML (and deferred scripts), then fires the event. Inside the handler you can safely query elements that appear earlier in the document.

Example 2 — readyState Guard for Late Scripts

Always-safe setup for async, module, or injected scripts (MDN pattern).

JavaScript
function init() {
  console.log("Setup running");
  console.log("readyState:", document.readyState);
}

if (document.readyState === "loading") {
  document.addEventListener("DOMContentLoaded", init);
} else {
  init();
}
Try It Yourself

How It Works

If parsing is still underway, wait for the event. If the document is already interactive or complete, run setup immediately so you do not miss the moment.

📈 Timing & Comparison

Contrast with load, see how sync work delays the event, and log the timeline.

Example 3 — DOMContentLoaded vs load

Both fire on a normal page load; DOMContentLoaded almost always comes first.

JavaScript
document.addEventListener("DOMContentLoaded", () => {
  console.log("1) DOMContentLoaded — DOM ready");
});

window.addEventListener("load", () => {
  console.log("2) load — full page (images, etc.)");
});

console.log("Listeners registered");
Try It Yourself

How It Works

Use DOMContentLoaded for DOM work. Reserve load for cases that truly need images and other sub-resources finished.

Example 4 — Sync Script Delays Parsing

MDN idea: a long synchronous script in the document delays parsing, so the event fires later.

JavaScript
document.addEventListener("DOMContentLoaded", () => {
  console.log("DOM fully loaded and parsed");
});

console.log("Heavy sync work starting...");
// Smaller loop for demos (MDN shows a huge loop to make the delay obvious)
let total = 0;
for (let i = 0; i < 5_000_000; i++) {
  total += i % 3;
}
console.log("Heavy sync work done, total hint:", total % 10);
// While this ran, the HTML parser was blocked — DOMContentLoaded waits.
Try It Yourself

How It Works

Classic parser-blocking scripts pause HTML parsing. Prefer defer, modules, or scripts at the end of body so the DOM can build sooner.

Example 5 — Loading Timeline Log

Log readystatechange, DOMContentLoaded, and load together (MDN live-demo idea).

JavaScript
const lines = [];
function log(msg) {
  lines.push(msg);
  console.log(msg);
}

document.addEventListener("readystatechange", () => {
  log("readystate: " + document.readyState);
});

document.addEventListener("DOMContentLoaded", () => {
  log("DOMContentLoaded");
});

window.addEventListener("load", () => {
  log("load");
  console.log("--- timeline ---");
  console.log(lines.join("\n"));
});
Try It Yourself

How It Works

Exact log lines can vary with when your script attaches, but the story stays the same: interactive / DOM ready comes before full load.

🚀 Common Use Cases

  • Binding click handlers after the markup exists.
  • Initializing UI widgets that query the DOM.
  • Reading form fields or data attributes from the page.
  • Hydrating client scripts without waiting for heavy images.
  • Guarding libraries that may load with async or after a dynamic import.

🔧 How It Works

1

HTML starts parsing

readyState is loading while the parser builds the tree.

Parse
2

Deferred scripts run

defer / module scripts finish after the document is parsed.

Scripts
3

DOMContentLoaded

Document fires the event; DOM queries are safe.

Ready
4

Later: window load

Images and remaining sub-resources finish; readyState becomes complete.

📝 Notes

  • Baseline Widely available — safe for production DOM setup.
  • No onDOMContentLoaded property; always use addEventListener.
  • Not cancelable; not a substitute for waiting on images (use load).
  • For late/async scripts, check document.readyState before listening.
  • Related learning: readyState, scripts, addEventListener(), JavaScript hub.

Universal Browser Support

Document DOMContentLoaded is marked Baseline Widely available on MDN (since July 2015). Logos use the shared browser-image-sprite.png sprite from this project. It is a standard Document event used across modern browsers.

Baseline · Widely available

Document DOMContentLoaded

Fires when the HTML is fully parsed and deferred scripts have run. Prefer it over load when you only need the DOM.

Universal Widely available
Google Chrome Full support · Desktop & Mobile
Full support
Mozilla Firefox Full support · Desktop & Mobile
Full support
Apple Safari Full support · macOS & iOS
Full support
Microsoft Edge Full support · Chromium & Legacy
Full support
Opera Full support · Modern versions
Full support
Internet Explorer Supported in IE9+ (prefer modern browsers)
Legacy
DOMContentLoaded Excellent

Bottom line: Use addEventListener("DOMContentLoaded", …) for DOM-ready setup. Guard async/late scripts with document.readyState. Use window load only when you need images and other sub-resources too.

Conclusion

DOMContentLoaded is the standard “DOM is ready” event. Use it to start interacting with markup without waiting for every image. Pair it with a readyState guard when your script might run late, and reach for load only when you truly need a fully loaded page.

Continue with fullscreenchange, readyState, or the JavaScript hub.

💡 Best Practices

✅ Do

  • Use DOMContentLoaded when you only need the DOM
  • Guard late/async scripts with document.readyState
  • Prefer defer / modules / end-of-body scripts to reduce waiting
  • Keep handlers short so first interaction stays snappy
  • Use load when image dimensions or full assets matter

❌ Don’t

  • Wait for load when DOMContentLoaded is enough
  • Expect an onDOMContentLoaded property (it does not exist)
  • Assume a late async script will still see the event without a guard
  • Block the parser with huge sync scripts in <head>
  • Treat “DOM ready” as “every image finished”

Key Takeaways

Knowledge Unlocked

Five things to remember about DOMContentLoaded

DOM ready signal — faster than waiting for full page load.

5
Core concepts
📷 02

Not images

use load later

Scope
🔒 03

readyState

guard late scripts

Safety
🚫 04

No on*

addEventListener

API
🚀 05

Baseline

use in production

Compat

❓ Frequently Asked Questions

It fires on Document when the HTML has been completely parsed and deferred scripts (defer and type="module") have downloaded and executed. It does not wait for images, subframes, or async scripts.
No. MDN marks it Baseline Widely available (since July 2015). It is a standard Document event — not Deprecated, Experimental, or Non-standard.
No. MDN notes there is no onDOMContentLoaded event handler property. Use document.addEventListener("DOMContentLoaded", handler).
DOMContentLoaded means the DOM is ready. The window load event waits for the full page including images and other sub-resources. Prefer DOMContentLoaded when you only need the DOM.
Check document.readyState. If it is still "loading", add a DOMContentLoaded listener; otherwise run your setup immediately. This matters for async scripts, dynamic imports, and injected scripts.
No. It is a generic Event and is not cancelable.
Did you know?

Many developers still wrap everything in window.onload out of habit. That waits for images too—often slowing first interaction for no reason. If your code only needs elements in the markup, DOMContentLoaded (or a script at the end of body) is the better default.

Next: Document fullscreenchange

Learn how to react when the page enters or leaves fullscreen mode.

fullscreenchange →

About the author

Mari Selvan M P
Mari Selvan M P 🔗

Developer, cloud engineer, and technical writer

  • Experience 12 years building web and cloud systems
  • Focus Full Stack Development, AWS, and Developer Education

I write practical tutorials so students and working developers can learn by doing—from databases and APIs to deployment on AWS.

5 people found this page helpful