runOnDocumentReady
Runs the provided function once the DOM is fully loaded.
1/**
2 * Runs the provided function once the DOM is fully loaded.
3 *
4 * @param callback - The function to run when the document is ready.
5 */
6export function runOnDocumentReady(callback: () => void): void {
7 if (
8 document.readyState === 'complete' || document.readyState === 'interactive'
9 ) {
10 callback();
11 } else {
12 document.addEventListener('DOMContentLoaded', callback, { once: true });
13 }
14}
Simplified DOM Readiness Handling
Eliminates the need to manually check
document.readyState
or wire up event listeners every time.Supports All Loading States
Works seamlessly whether the script is executed before or after the DOM has loaded.
Avoids Redundant Calls
Uses the
{ once: true }
option to ensure the callback is invoked only once, preventing unexpected side effects.Zero Dependencies
A lightweight utility that avoids jQuery or other DOM libraries while providing similar convenience.
Tests | Examples
1let originalReadyState: PropertyDescriptor | undefined;
2
3beforeEach(() => {
4 originalReadyState = Object.getOwnPropertyDescriptor(document, 'readyState');
5});
6
7afterEach(() => {
8 if (originalReadyState) {
9 Object.defineProperty(document, 'readyState', originalReadyState);
10 }
11});
12
13test('executes immediately if document is already "complete"', () => {
14 Object.defineProperty(document, 'readyState', {
15 configurable: true,
16 get: () => 'complete',
17 });
18
19 const mockFn = jest.fn();
20 runOnDocumentReady(mockFn);
21
22 expect(mockFn).toHaveBeenCalledTimes(1);
23});
24
25test('executes immediately if document is already "interactive"', () => {
26 Object.defineProperty(document, 'readyState', {
27 configurable: true,
28 get: () => 'interactive',
29 });
30
31 const mockFn = jest.fn();
32 runOnDocumentReady(mockFn);
33
34 expect(mockFn).toHaveBeenCalledTimes(1);
35});
36
37test('adds DOMContentLoaded listener if document is "loading"', () => {
38 Object.defineProperty(document, 'readyState', {
39 configurable: true,
40 get: () => 'loading',
41 });
42
43 const mockFn = jest.fn();
44 runOnDocumentReady(mockFn);
45
46 document.dispatchEvent(new Event('DOMContentLoaded'));
47
48 expect(mockFn).toHaveBeenCalledTimes(1);
49});
Common Use Cases
Initializing UI Components
Run setup logic for widgets, tooltips, carousels, or modals after the DOM is ready.
DOM Query and Manipulation
Safely access and modify elements without risking null references.
Analytics and Tracking Scripts
Start tracking page interactions or impressions only after DOM is available.
Polyfill or Fallback Injection
Apply compatibility fixes or style patches once the base layout is guaranteed to be in place.