DOM parity

Chrome is the oracle. 192 features — interfaces, members and behaviours — are put to all four runtimes, and 46 behaviour cases run the same code in each.

RuntimeAgrees with Chrome
esdev168 / 19288%
jsdom155 / 19281%
happy-dom158 / 19282%

By area

AreaFeaturesesdevjsdomhappy-dom
tree44434036
traversal13111210
cascade24201217
events24232024
components17171213
parsing1281211
selectors13131312
forms14141414
window31192021

Behaviour cases

44 of 46 cases match Chrome exactly, and 2 is a documented limit.

CaseAreaesdevjsdomhappy-dom
append-and-replace-childrentreeyesyesyes
fragment-contents-move-on-appendtreeyesyesyes
deep-clone-is-independenttreeyesyesyes
collections-stay-livetreeyesyesyes
capturing-and-bubbling-ordereventsyesyesyes
cancelled-event-returns-falseeventsyesyesyes
inline-handlers-run-for-modern-eventseventsyesyesyes
once-listener-runs-onceeventsyesyesyes
stopped-propagation-does-not-reach-parenteventsyesyesyes
fragment-serializes-text-and-attributesparsingyesyesyes
raw-text-is-not-parsed-as-elementsparsingyesyesyes
svg-attributes-and-self-closing-childrenparsingyesyesno
namespace-attribute-access-and-replacementtreeyesyesyes
dataset-reflects-data-attributestreeyesyesno
create-element-ns-preserves-identitytreeyesyesyes
omitted-tags-html-allows-are-filled-inparsingyesyesno
table-collections-follow-the-section-ordertreeyesyesno
fragment-structure-follows-its-context-elementparsingyesyesyes
malformed-markup-is-a-strict-esdev-limitparsingnoyesyes
compound-and-attribute-selectorselectorsyesyesyes
logical-selector-listselectorsyesyesyes
structural-selectorselectorsyesyesyes
invalid-selector-throws-syntax-errorselectorsyesyesno
nth-child-counts-only-the-of-listselectorsyesnoyes
defined-pseudo-class-follows-the-definitioncomponentsyesyesno
adjacent-insertion-lands-at-four-positionstreeyesyesyes
declarative-shadow-root-attaches-only-through-set-html-unsafecomponentsyesnono
form-associated-custom-element-joins-its-formcomponentsyesnono
custom-state-matches-the-state-pseudo-classcomponentsyesnono
origin-importance-specificity-and-order-decide-the-winnercascadeyesyesyes
inheritance-and-user-agent-defaultscascadeyesnono
media-and-supports-conditions-gate-their-rulescascadeyesnono
constructed-sheets-apply-while-adoptedcascadeyesnono
a-shadow-root-is-styled-by-its-own-sheetscascadeyesnono
nesting-resolves-against-its-parent-rulecascadeyesnono
geometry-answers-zero-and-rendering-is-knowablecascadenonono
input-indeterminate-is-non-reflecting-stateformsyesyesyes
form-owner-follows-form-attributeformsyesyesyes
form-and-submitter-settings-reflectformsyesnoyes
form-data-uses-successful-controlsformsyesyesyes
required-control-blocks-submitformsyesyesyes
submitter-no-validate-bypasses-constraintsformsyesnoyes
reset-control-restores-default-valueformsyesyesyes
radio-click-is-exclusive-by-form-ownerformsyesyesyes
label-click-activates-nested-checkboxformsyesyesyes
disabled-fieldset-excludes-validation-and-dataformsyesyesno

Closer to Chrome than an emulator

39 features where esdev matches Chrome and jsdom or happy-dom does not.

FeatureChrome & esdevjsdomhappy-dom
CDATASectionyesyesno
DOMImplementationyesyesno
DOMTokenListyesyesno
DOMStringMapyesyesno
CharacterData in the prototype chainText < CharacterData < Node < EventTarget < ObjectText < CharacterData < Node < EventTarget < ObjectText < Text < CharacterData < Node < EventTarget < Object
document.doctypehtmlhtmlnone
Element.setHTMLUnsafeyesnono
Element.getHTMLyesnoyes
Element.checkVisibilityyesnono
StaticRangeyesyesno
AbstractRangeyesyesno
Range.getBoundingClientRectyesnoyes
element scroll offsets0,0,false40,0,true40,0,false
DragEventyesnoyes
ClipboardEventyesnoyes
IntersectionObserveryesnoyes
ResizeObserveryesnoyes
manual slot assignmentyesnoyes
shadow root reports clonable and serializabletrue,false,true,false
setHTMLUnsafe attaches a declarative rootattachedthrows:TypeErrorthrows:TypeError
attachInternalsyesyesno
form-associated custom elementyesnothrows:TypeError
CustomStateSetyesnono
omitted paragraph end tag<p>one</p><p>two</p><p>one</p><p>two</p><p>one<p>two</p></p>
invalid selector throwsSyntaxErrorSyntaxErrorno throw
adoptedStyleSheets appliesrgb(1, 2, 3)rgb(0, 0, 0)rgb(1, 2, 3)
user-agent display defaultsblock,inlineblock,inlineblock,
no computed style outside the treeyesnoyes
@media follows the viewportrgb(7, 7, 7)rgb(0, 0, 0)rgb(7, 7, 7)
matchMedia answerstrue,falsethrows:TypeErrortrue,false
CSS.supportstrue,trueundefined,undefinedtrue,true
CSS nesting resolvesrgb(2, 2, 2)rgb(1, 1, 1)``
scrollIntoViewyesnoyes
structuredCloneyesnono
fetchyesnoyes
WebSocketyesyesno
Workeryesnono
URL.createObjectURLyesnoyes
MathMLElementyesnono

Differences from Chrome

24 features, each with its reason. There are no others.

No layout: there is no box model, so there is nothing to measure or scroll.

FeatureChromeesdev
innerTextyesno
getBoundingClientRect measuresmeasuredzero
offsetWidth measuresmeasuredzero

Legacy or superseded by a modern API that is implemented.

FeatureChromeesdev
NodeIteratoryesno
XPathEvaluator (document.evaluate)yesno
TouchEventyesno
XMLSerializeryesno
document.writeyesno

Deliberately strict: malformed markup is refused rather than repaired.

FeatureChromeesdev
malformed HTML<p><i>unclosed</i></p>throws:SyntaxError
misnested tags<b><i>x</i></b>throws:SyntaxError

No rendering: the top layer, animations and transitions have nothing to paint.

FeatureChromeesdev
Element.animate (WAAPI)yesno
showPopoveryesno
dialog.showModalyesno
document.startViewTransitionyesno

Specified values only: resolving one needs layout and a font.

FeatureChromeesdev
resolved font size32px2em

Harness artifact: Chrome ran the probe on about:blank, which is an opaque, insecure origin.

FeatureChromeesdev
localStoragethrows:SecurityErroryes
crypto.randomUUIDnoyes

No host resource: this DOM reaches no network, no file and no browsing context.

FeatureChromeesdev
document.cookieyesno
XMLHttpRequestyesno
File / FileReaderyesno
alertyesno
Imageyesno
canvas.getContextcontextmissing
iframe.contentWindowwindownull
Last updated on
Edit this page