0
# DOM APIs
1
2
The `window` object in jsdom provides a comprehensive browser-like environment with standard web APIs. This document covers the major DOM and browser APIs available through `dom.window`.
3
4
## Overview
5
6
Access the window object via the `window` property of a JSDOM instance:
7
8
```javascript
9
const { JSDOM } = require("jsdom");
10
11
const dom = new JSDOM(`<!DOCTYPE html><body><div id="app"></div></body>`);
12
const { window } = dom;
13
const { document } = window;
14
15
// Use standard DOM APIs
16
const app = document.getElementById("app");
17
app.innerHTML = "<h1>Hello, jsdom!</h1>";
18
```
19
20
## Major API Categories
21
22
### Core DOM APIs
23
24
Standard DOM manipulation interfaces matching browser behavior.
25
26
#### Document and Nodes
27
28
```javascript { .api }
29
/**
30
* Core DOM interfaces
31
*/
32
interface Window {
33
/** The Document interface */
34
document: Document;
35
36
/** DOM node types */
37
Node: typeof Node;
38
Element: typeof Element;
39
Document: typeof Document;
40
DocumentFragment: typeof DocumentFragment;
41
Text: typeof Text;
42
Comment: typeof Comment;
43
CDATASection: typeof CDATASection;
44
ProcessingInstruction: typeof ProcessingInstruction;
45
DocumentType: typeof DocumentType;
46
47
/** HTML element constructors */
48
HTMLElement: typeof HTMLElement;
49
HTMLDivElement: typeof HTMLDivElement;
50
HTMLSpanElement: typeof HTMLSpanElement;
51
HTMLParagraphElement: typeof HTMLParagraphElement;
52
HTMLAnchorElement: typeof HTMLAnchorElement;
53
HTMLImageElement: typeof HTMLImageElement;
54
HTMLFormElement: typeof HTMLFormElement;
55
HTMLInputElement: typeof HTMLInputElement;
56
HTMLButtonElement: typeof HTMLButtonElement;
57
HTMLSelectElement: typeof HTMLSelectElement;
58
HTMLTextAreaElement: typeof HTMLTextAreaElement;
59
HTMLScriptElement: typeof HTMLScriptElement;
60
HTMLLinkElement: typeof HTMLLinkElement;
61
HTMLStyleElement: typeof HTMLStyleElement;
62
HTMLIFrameElement: typeof HTMLIFrameElement;
63
HTMLCanvasElement: typeof HTMLCanvasElement;
64
// ... and many more HTML element types
65
}
66
```
67
68
**Usage:**
69
70
```javascript
71
const { document } = dom.window;
72
73
// Create elements
74
const div = document.createElement("div");
75
const text = document.createTextNode("Hello");
76
const comment = document.createComment("Comment");
77
const fragment = document.createDocumentFragment();
78
79
// Manipulate DOM
80
div.appendChild(text);
81
document.body.appendChild(div);
82
83
// Query DOM
84
const elements = document.querySelectorAll("div");
85
const element = document.getElementById("app");
86
const byClass = document.getElementsByClassName("container");
87
const byTag = document.getElementsByTagName("p");
88
```
89
90
#### Node Collections and Traversal
91
92
```javascript { .api }
93
/**
94
* Node collections and traversal interfaces
95
*/
96
interface Window {
97
/** Live collection of nodes */
98
NodeList: typeof NodeList;
99
100
/** Live collection of HTML elements */
101
HTMLCollection: typeof HTMLCollection;
102
103
/** Tree traversal interfaces */
104
NodeIterator: typeof NodeIterator;
105
TreeWalker: typeof TreeWalker;
106
107
/** Named node map for attributes */
108
NamedNodeMap: typeof NamedNodeMap;
109
}
110
```
111
112
**Usage:**
113
114
```javascript
115
const { document } = dom.window;
116
117
// Create tree walker
118
const walker = document.createTreeWalker(
119
document.body,
120
dom.window.NodeFilter.SHOW_ELEMENT
121
);
122
123
let node;
124
while (node = walker.nextNode()) {
125
console.log(node.nodeName);
126
}
127
128
// Create node iterator
129
const iterator = document.createNodeIterator(
130
document.body,
131
dom.window.NodeFilter.SHOW_TEXT
132
);
133
134
let textNode;
135
while (textNode = iterator.nextNode()) {
136
console.log(textNode.textContent);
137
}
138
```
139
140
#### Attributes and Ranges
141
142
```javascript { .api }
143
/**
144
* Attribute and range interfaces
145
*/
146
interface Window {
147
/** Attribute node */
148
Attr: typeof Attr;
149
150
/** Range interface for selections */
151
Range: typeof Range;
152
153
/** Selection interface */
154
Selection: typeof Selection;
155
}
156
```
157
158
**Usage:**
159
160
```javascript
161
const { document } = dom.window;
162
163
// Work with attributes
164
const div = document.createElement("div");
165
div.setAttribute("class", "container");
166
const attr = div.getAttributeNode("class");
167
console.log(attr.value); // "container"
168
169
// Work with ranges
170
const range = document.createRange();
171
range.selectNodeContents(document.body);
172
console.log(range.toString());
173
174
// Work with selection
175
const selection = dom.window.getSelection();
176
selection.addRange(range);
177
```
178
179
### Events
180
181
Complete event system with standard event types and propagation.
182
183
#### Event Constructors
184
185
```javascript { .api }
186
/**
187
* Event interfaces
188
*/
189
interface Window {
190
/** Base event classes */
191
EventTarget: typeof EventTarget;
192
Event: typeof Event;
193
CustomEvent: typeof CustomEvent;
194
195
/** UI events */
196
UIEvent: typeof UIEvent;
197
MouseEvent: typeof MouseEvent;
198
KeyboardEvent: typeof KeyboardEvent;
199
FocusEvent: typeof FocusEvent;
200
InputEvent: typeof InputEvent;
201
WheelEvent: typeof WheelEvent;
202
PointerEvent: typeof PointerEvent;
203
TouchEvent: typeof TouchEvent;
204
205
/** Form events */
206
SubmitEvent: typeof SubmitEvent;
207
208
/** Page events */
209
PopStateEvent: typeof PopStateEvent;
210
HashChangeEvent: typeof HashChangeEvent;
211
PageTransitionEvent: typeof PageTransitionEvent;
212
BeforeUnloadEvent: typeof BeforeUnloadEvent;
213
214
/** Other events */
215
ErrorEvent: typeof ErrorEvent;
216
MessageEvent: typeof MessageEvent;
217
ProgressEvent: typeof ProgressEvent;
218
StorageEvent: typeof StorageEvent;
219
PromiseRejectionEvent: typeof PromiseRejectionEvent;
220
}
221
```
222
223
**Usage:**
224
225
```javascript
226
const { document } = dom.window;
227
228
// Add event listeners
229
const button = document.createElement("button");
230
button.textContent = "Click me";
231
232
button.addEventListener("click", (event) => {
233
console.log("Button clicked!", event.type);
234
});
235
236
// Dispatch events
237
const event = new dom.window.MouseEvent("click", {
238
bubbles: true,
239
cancelable: true
240
});
241
button.dispatchEvent(event);
242
243
// Custom events
244
const customEvent = new dom.window.CustomEvent("myevent", {
245
detail: { data: "custom data" }
246
});
247
document.dispatchEvent(customEvent);
248
249
document.addEventListener("myevent", (e) => {
250
console.log(e.detail.data); // "custom data"
251
});
252
```
253
254
### Window and Navigation
255
256
Browser window properties and navigation interfaces.
257
258
#### Location and History
259
260
```javascript { .api }
261
/**
262
* Navigation interfaces
263
*/
264
interface Window {
265
/** Current location */
266
location: Location;
267
268
/** Session history */
269
history: History;
270
271
/** Navigator information */
272
navigator: Navigator;
273
274
/** Screen information */
275
screen: Screen;
276
277
/** Window properties */
278
top: Window;
279
parent: Window;
280
self: Window;
281
window: Window;
282
}
283
```
284
285
**Usage:**
286
287
```javascript
288
const { window } = dom;
289
290
// Location properties
291
console.log(window.location.href);
292
console.log(window.location.hostname);
293
console.log(window.location.pathname);
294
console.log(window.location.search);
295
console.log(window.location.hash);
296
297
// History methods
298
window.history.pushState({ page: 1 }, "Title", "/page1");
299
window.history.replaceState({ page: 2 }, "Title", "/page2");
300
window.history.back();
301
window.history.forward();
302
303
// Navigator
304
console.log(window.navigator.userAgent);
305
console.log(window.navigator.platform);
306
307
// Screen
308
console.log(window.screen.width);
309
console.log(window.screen.height);
310
```
311
312
**Note:** jsdom has limited navigation support - assigning to `window.location.href` does not navigate. Use `dom.reconfigure({ url })` or create new JSDOM instances for navigation.
313
314
### Timers and Animation
315
316
Asynchronous execution and animation frame APIs.
317
318
```javascript { .api }
319
/**
320
* Timer and animation functions
321
*/
322
interface Window {
323
/** Schedule code execution */
324
setTimeout(callback: Function, delay?: number, ...args: any[]): number;
325
clearTimeout(id: number): void;
326
327
setInterval(callback: Function, delay?: number, ...args: any[]): number;
328
clearInterval(id: number): void;
329
330
setImmediate(callback: Function, ...args: any[]): number;
331
clearImmediate(id: number): void;
332
333
/** Animation frames (requires pretendToBeVisual: true) */
334
requestAnimationFrame?(callback: (timestamp: number) => void): number;
335
cancelAnimationFrame?(id: number): void;
336
}
337
```
338
339
**Usage:**
340
341
```javascript
342
const { window } = dom;
343
344
// Timers
345
const timeoutId = window.setTimeout(() => {
346
console.log("Timeout executed");
347
}, 100);
348
349
const intervalId = window.setInterval(() => {
350
console.log("Interval tick");
351
}, 500);
352
353
// Clear timers
354
window.clearTimeout(timeoutId);
355
window.clearInterval(intervalId);
356
357
// Immediate execution
358
window.setImmediate(() => {
359
console.log("Immediate executed");
360
});
361
362
// Animation frames (with pretendToBeVisual)
363
const dom2 = new JSDOM(``, { pretendToBeVisual: true });
364
dom2.window.requestAnimationFrame((timestamp) => {
365
console.log("Animation frame:", timestamp);
366
});
367
368
// Shut down jsdom
369
window.close(); // Terminates all timers
370
```
371
372
### Web Storage
373
374
localStorage and sessionStorage APIs.
375
376
```javascript { .api }
377
/**
378
* Web Storage interfaces
379
*/
380
interface Window {
381
/** Persistent local storage */
382
localStorage: Storage;
383
384
/** Session storage */
385
sessionStorage: Storage;
386
}
387
388
interface Storage {
389
readonly length: number;
390
getItem(key: string): string | null;
391
setItem(key: string, value: string): void;
392
removeItem(key: string): void;
393
clear(): void;
394
key(index: number): string | null;
395
}
396
```
397
398
**Usage:**
399
400
```javascript
401
const { window } = dom;
402
403
// localStorage
404
window.localStorage.setItem("username", "alice");
405
window.localStorage.setItem("theme", "dark");
406
407
console.log(window.localStorage.getItem("username")); // "alice"
408
console.log(window.localStorage.length); // 2
409
410
window.localStorage.removeItem("theme");
411
window.localStorage.clear();
412
413
// sessionStorage
414
window.sessionStorage.setItem("token", "abc123");
415
console.log(window.sessionStorage.getItem("token")); // "abc123"
416
417
// Storage events
418
window.addEventListener("storage", (event) => {
419
console.log("Storage changed:", event.key, event.newValue);
420
});
421
```
422
423
### Parsing and Serialization
424
425
HTML/XML parsing and serialization interfaces.
426
427
```javascript { .api }
428
/**
429
* Parsing and serialization interfaces
430
*/
431
interface Window {
432
/** Parse HTML/XML strings */
433
DOMParser: typeof DOMParser;
434
435
/** Serialize DOM to XML */
436
XMLSerializer: typeof XMLSerializer;
437
}
438
```
439
440
**Usage:**
441
442
```javascript
443
const { window } = dom;
444
445
// Parse HTML
446
const parser = new window.DOMParser();
447
const doc = parser.parseFromString("<p>Hello</p>", "text/html");
448
console.log(doc.querySelector("p").textContent); // "Hello"
449
450
// Parse XML
451
const xmlDoc = parser.parseFromString("<root><item/></root>", "application/xml");
452
console.log(xmlDoc.documentElement.nodeName); // "root"
453
454
// Serialize to XML
455
const serializer = new window.XMLSerializer();
456
const xmlString = serializer.serializeToString(doc.documentElement);
457
console.log(xmlString); // "<html>...</html>"
458
```
459
460
### File and Binary APIs
461
462
File, Blob, and FileReader interfaces.
463
464
```javascript { .api }
465
/**
466
* File and binary data interfaces
467
*/
468
interface Window {
469
/** Binary data container */
470
Blob: typeof Blob;
471
472
/** File representation */
473
File: typeof File;
474
475
/** List of files */
476
FileList: typeof FileList;
477
478
/** Read file contents */
479
FileReader: typeof FileReader;
480
}
481
```
482
483
**Usage:**
484
485
```javascript
486
const { window } = dom;
487
488
// Create Blob
489
const blob = new window.Blob(["Hello, world!"], { type: "text/plain" });
490
console.log(blob.size); // 13
491
console.log(blob.type); // "text/plain"
492
493
// Create File
494
const file = new window.File(["content"], "test.txt", {
495
type: "text/plain",
496
lastModified: Date.now()
497
});
498
console.log(file.name); // "test.txt"
499
500
// Read file
501
const reader = new window.FileReader();
502
reader.onload = (event) => {
503
console.log("File contents:", event.target.result);
504
};
505
reader.readAsText(blob);
506
```
507
508
### Network APIs
509
510
WebSocket and basic network interfaces.
511
512
```javascript { .api }
513
/**
514
* Network interfaces
515
*/
516
interface Window {
517
/** WebSocket connection */
518
WebSocket: typeof WebSocket;
519
520
/** Fetch API headers */
521
Headers: typeof Headers;
522
523
/** Abort controller for requests */
524
AbortController: typeof AbortController;
525
AbortSignal: typeof AbortSignal;
526
}
527
```
528
529
**Usage:**
530
531
```javascript
532
const { window } = dom;
533
534
// WebSocket
535
const ws = new window.WebSocket("wss://example.com/socket");
536
537
ws.onopen = () => {
538
console.log("WebSocket connected");
539
ws.send("Hello server");
540
};
541
542
ws.onmessage = (event) => {
543
console.log("Received:", event.data);
544
};
545
546
ws.onerror = (error) => {
547
console.error("WebSocket error:", error);
548
};
549
550
ws.close();
551
552
// Headers
553
const headers = new window.Headers();
554
headers.append("Content-Type", "application/json");
555
headers.append("Authorization", "Bearer token");
556
557
console.log(headers.get("Content-Type")); // "application/json"
558
559
// AbortController
560
const controller = new window.AbortController();
561
const signal = controller.signal;
562
563
// Use signal with APIs that support it
564
// controller.abort(); // Cancel operation
565
```
566
567
### Custom Elements
568
569
Custom elements and shadow DOM APIs.
570
571
```javascript { .api }
572
/**
573
* Custom elements interfaces
574
*/
575
interface Window {
576
/** Custom elements registry */
577
customElements: CustomElementRegistry;
578
579
/** Element internals */
580
ElementInternals: typeof ElementInternals;
581
}
582
```
583
584
**Usage:**
585
586
```javascript
587
const { window } = dom;
588
589
// Define custom element
590
class MyElement extends window.HTMLElement {
591
constructor() {
592
super();
593
this.attachShadow({ mode: "open" });
594
}
595
596
connectedCallback() {
597
this.shadowRoot.innerHTML = "<p>Custom element content</p>";
598
}
599
}
600
601
// Register custom element
602
window.customElements.define("my-element", MyElement);
603
604
// Use custom element
605
const custom = dom.window.document.createElement("my-element");
606
dom.window.document.body.appendChild(custom);
607
```
608
609
### Console
610
611
Console API connected to VirtualConsole.
612
613
```javascript { .api }
614
/**
615
* Console interface
616
*/
617
interface Window {
618
console: Console;
619
}
620
621
interface Console {
622
log(...args: any[]): void;
623
error(...args: any[]): void;
624
warn(...args: any[]): void;
625
info(...args: any[]): void;
626
debug(...args: any[]): void;
627
trace(...args: any[]): void;
628
assert(condition: boolean, ...args: any[]): void;
629
clear(): void;
630
count(label?: string): void;
631
countReset(label?: string): void;
632
dir(obj: any, options?: object): void;
633
dirxml(...args: any[]): void;
634
group(...args: any[]): void;
635
groupCollapsed(...args: any[]): void;
636
groupEnd(): void;
637
table(data: any): void;
638
time(label?: string): void;
639
timeLog(label?: string, ...args: any[]): void;
640
timeEnd(label?: string): void;
641
}
642
```
643
644
**Usage:**
645
646
```javascript
647
const { window } = dom;
648
649
// Console methods
650
window.console.log("Log message");
651
window.console.error("Error message");
652
window.console.warn("Warning message");
653
window.console.info("Info message");
654
655
window.console.time("operation");
656
// ... do something ...
657
window.console.timeEnd("operation");
658
659
window.console.group("Group");
660
window.console.log("Inside group");
661
window.console.groupEnd();
662
663
window.console.table([
664
{ name: "Alice", age: 30 },
665
{ name: "Bob", age: 25 }
666
]);
667
```
668
669
### Other Web APIs
670
671
Additional web platform APIs.
672
673
```javascript { .api }
674
/**
675
* Additional web APIs
676
*/
677
interface Window {
678
/** URL manipulation */
679
URL: typeof URL;
680
URLSearchParams: typeof URLSearchParams;
681
682
/** Text encoding */
683
TextEncoder: typeof TextEncoder;
684
TextDecoder: typeof TextDecoder;
685
686
/** Crypto API */
687
crypto: Crypto;
688
689
/** DOMException */
690
DOMException: typeof DOMException;
691
692
/** Form data */
693
FormData: typeof FormData;
694
}
695
```
696
697
**Usage:**
698
699
```javascript
700
const { window } = dom;
701
702
// URL
703
const url = new window.URL("https://example.com/path?query=value#hash");
704
console.log(url.hostname); // "example.com"
705
console.log(url.searchParams.get("query")); // "value"
706
707
// URLSearchParams
708
const params = new window.URLSearchParams("foo=bar&baz=qux");
709
console.log(params.get("foo")); // "bar"
710
params.append("new", "value");
711
712
// TextEncoder/Decoder
713
const encoder = new window.TextEncoder();
714
const bytes = encoder.encode("Hello");
715
console.log(bytes); // Uint8Array
716
717
const decoder = new window.TextDecoder();
718
const text = decoder.decode(bytes);
719
console.log(text); // "Hello"
720
721
// Crypto
722
const randomValues = new Uint8Array(16);
723
window.crypto.getRandomValues(randomValues);
724
console.log(randomValues);
725
726
// FormData
727
const form = window.document.createElement("form");
728
const formData = new window.FormData(form);
729
formData.append("username", "alice");
730
formData.append("email", "alice@example.com");
731
```
732
733
## Canvas Support
734
735
jsdom supports the Canvas API via the optional `canvas` peer dependency.
736
737
To enable canvas support:
738
739
```bash
740
npm install canvas
741
```
742
743
Once installed, `<canvas>` elements have the full Canvas API:
744
745
```javascript
746
const { JSDOM } = require("jsdom");
747
748
const dom = new JSDOM(`<!DOCTYPE html><canvas id="canvas"></canvas>`);
749
const canvas = dom.window.document.getElementById("canvas");
750
751
// If canvas package is installed
752
if (canvas.getContext) {
753
const ctx = canvas.getContext("2d");
754
ctx.fillStyle = "red";
755
ctx.fillRect(10, 10, 100, 100);
756
757
// Export to buffer
758
canvas.toBuffer((err, buffer) => {
759
// PNG buffer
760
});
761
}
762
```
763
764
## Limitations
765
766
### No Layout Calculation
767
768
jsdom does not implement layout or rendering. Layout-related properties return placeholder values:
769
770
- `getBoundingClientRect()` returns zeros
771
- `offsetWidth`, `offsetHeight`, `offsetTop`, etc. return 0
772
- `clientWidth`, `clientHeight` return 0
773
- `getComputedStyle()` returns default values
774
775
**Workaround:** Mock layout values with `Object.defineProperty()`:
776
777
```javascript
778
Object.defineProperty(element, "offsetWidth", {
779
get: () => 100
780
});
781
```
782
783
### No Navigation
784
785
Assigning to `window.location.href` does not navigate or create new documents.
786
787
**Workaround:** Create new JSDOM instances for each page:
788
789
```javascript
790
async function navigate(url) {
791
const dom = await JSDOM.fromURL(url);
792
return dom;
793
}
794
```
795
796
## Complete Example
797
798
```javascript
799
const { JSDOM } = require("jsdom");
800
801
const dom = new JSDOM(`
802
<!DOCTYPE html>
803
<html>
804
<head><title>Test Page</title></head>
805
<body>
806
<div id="app">
807
<h1>Welcome</h1>
808
<button id="btn">Click Me</button>
809
<ul id="list"></ul>
810
</div>
811
</body>
812
</html>
813
`, {
814
url: "https://example.com/",
815
referrer: "https://google.com/",
816
runScripts: "outside-only",
817
pretendToBeVisual: true
818
});
819
820
const { window } = dom;
821
const { document } = window;
822
823
// DOM manipulation
824
const button = document.getElementById("btn");
825
const list = document.getElementById("list");
826
827
// Event handling
828
button.addEventListener("click", () => {
829
console.log("Button clicked!");
830
831
const item = document.createElement("li");
832
item.textContent = `Item ${list.children.length + 1}`;
833
list.appendChild(item);
834
});
835
836
// Trigger event
837
button.click();
838
839
// Storage
840
window.localStorage.setItem("visited", "true");
841
842
// Timers
843
window.setTimeout(() => {
844
console.log("Timer executed");
845
}, 100);
846
847
// Serialize result
848
console.log(dom.serialize());
849
850
// Clean up
851
window.close();
852
```
853