DOM parity

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

RuntimeAgrees with Chrome
esdev217 / 23493%
jsdom184 / 23479%
happy-dom185 / 23479%

By area

AreaFeaturesesdevjsdomhappy-dom
tree55554944
traversal14131311
selectors14141413
cascade26231217
window36292426
events26242225
components32322020
parsing1391211
forms18181818

Behaviour cases

119 of 121 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
list-interfaces-iterate-as-web-idl-declarestreeyesnono
details-dialog-and-popover-toggle-alikeeventsyesnono
a-removed-subtree-stays-observed-until-deliveryeventsyesnono
an-observer-that-throws-is-reported-and-the-rest-still-runeventsyesyesyes
a-click-runs-activation-behaviour-however-it-is-dispatchedeventsyesnono
keyboard-and-mouse-events-carry-their-modifierseventsyesyesno
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
an-equal-specificity-tie-goes-to-the-later-sheetcascadeyesnono
floats-positioned-boxes-and-flex-items-are-blockifiedcascadeyesnono
inner-text-is-the-rendered-textcascadeyesnono
media-lists-and-grouping-rules-are-their-interfacescascadeyesnono
nesting-resolves-against-its-parent-rulecascadeyesnono
geometry-answers-zero-and-rendering-is-knowablecascadenonono
html-names-are-case-insensitivetreeyesyesyes
bare-constructors-and-fragment-lookupstreeyesnoyes
a-radio-group-is-exclusive-on-the-checked-setterformsyesyesyes
escapes-in-an-identifierselectorsyesyesno
an-unknown-property-is-not-a-declarationcascadeyesnono
a-node-iterator-walks-and-steps-backtraversalyesyesno
a-secondary-document-is-a-whole-documenttreeyesyesno
reaction-order-on-creation-and-connectioncomponentsyesyesyes
an-existing-element-upgrades-when-it-is-definedcomponentsyesyesno
parsed-children-upgrade-in-tree-ordercomponentsyesyesyes
the-registry-answers-about-a-definitioncomponentsyesyesno
an-element-can-be-upgraded-on-demandcomponentsyesyesno
constants-node-values-and-odd-nodes-serializetreeyesnono
every-way-an-attribute-changes-is-one-changetreeyesnono
form-and-select-collections-are-their-interfacestreeyesyesno
character-data-is-edited-in-placetreeyesnono
a-range-edits-text-through-character-datatreeyesyesno
slots-assign-and-flattencomponentsyesyesno
flattening-recurses-through-a-slotted-slotcomponentsyesyesno
a-slot-reports-a-changecomponentsyesyesyes
internals-reflect-aria-and-form-statecomponentsyesnono
a-clonable-shadow-root-is-clonedcomponentsyesnoyes
shadow-styles-reach-the-host-and-the-slottedcomponentsyesnono
a-constructor-is-refused-when-it-misbehavescomponentsyesyesno
an-element-moved-between-documents-is-adoptedcomponentsyesyesno
attributes-report-their-namespace-and-old-valuecomponentsyesyesno
a-shadow-host-refuses-a-second-root-and-the-wrong-elementcomponentsyesyesno
focus-inside-a-root-is-reported-from-both-sidescomponentsyesyesyes
an-event-is-retargeted-and-a-closed-root-hides-its-pathcomponentsyesyesno
aria-reflects-through-attributes-and-internalscomponentsyesyesno
a-slot-change-follows-the-slot-attributecomponentsyesyesyes
a-template-holds-a-component-and-clones-itcomponentsyesnono
adoption-and-a-shadow-sweep-report-oncecomponentsyesyesno
a-closed-root-serializes-when-it-is-asked-forcomponentsyesnono
a-reset-clears-a-custom-elements-valuecomponentsyesnono
a-disabled-attribute-and-a-throwing-constructorcomponentsyesnono
moveBefore-keeps-state-and-connectiontreeyesnono
a-document-is-parsed-from-markupparsingyesnono
a-dialog-opens-closes-and-returnscomponentsyesnono
a-popover-toggles-and-reports-its-statecomponentsyesnono
a-command-button-acts-on-the-element-it-namescomponentsyesnono
an-attribute-name-is-lowercased-for-html-onlytreeyesyesyes
a-document-has-no-text-contenttreeyesyesno
internal-work-does-not-read-the-attributes-accessortreeyesyesyes
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
cancel-bubble-is-the-stop-propagation-flageventsyesyesno
nodes-stringify-as-their-interfacetreeyesnono
svg-elements-get-their-own-interfaceparsingyesnoyes
a-customized-built-in-upgrades-its-built-incomponentsyesnono
custom-properties-substitute-into-computed-valuescascadeyesnono
a-value-a-property-cannot-take-is-droppedcascadeyesnono
shorthands-expand-into-longhandscascadeyesnono
named-access-on-the-windowtreeyesyesno
an-inline-declaration-holds-its-longhandscascadeyesnono
a-controls-value-is-filtered-not-rewrittenformsyesnono
interface-members-can-be-redefinedtreeyesyesyes
an-attribute-handler-is-compiled-and-a-throw-is-reportedeventsyesnono
a-colour-resolves-when-it-is-computedcascadeyesnono
a-value-is-checked-against-the-propertycascadeyesnono
colour-functions-are-canonicalcascadeyesnono
lengths-are-absolute-when-they-can-becascadeyesnono
the-layered-shorthands-expand-toocascadeyesnono
a-computed-shorthand-comes-from-its-longhandscascadeyesnono
a-declaration-block-holds-longhandscascadeyesnono
every-html-name-has-its-interfacetreeyesyesyes
a-template-content-lives-in-its-own-documenttreeyesyesno

Closer to Chrome than an emulator

64 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
innerTextyesnoyes
document.hasFocus()yesnoyes
implementation.createDocumentsvg/http://www.w3.org/2000/svgsvg/http://www.w3.org/2000/svghtml/http://www.w3.org/1999/xhtml
unknown property is undefinedundefined/false/falseundefined/false/undefinedundefined/false/true
keyword initial valuesnone,1,visible,0px,auto,,,,,,,,
StaticRangeyesyesno
AbstractRangeyesyesno
Range.getBoundingClientRectyesnoyes
element scroll offsets0,0,false40,0,true40,0,false
DragEventyesnoyes
ClipboardEventyesnoyes
createEvent by interface nameEvent/InvalidStateError/probe-created/trueEvent/InvalidStateError/probe-created/trueEvent/dispatched/probe-created/true
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
one constructor, one nameNotSupportedErrorNotSupportedErrorDOMException
node.assignedSlotyesyesno
attachShadow refuses a non-hostNotSupportedErrorNotSupportedErrorattached
:host and ::slottedrgb(9, 9, 9)/italicrgb(0, 0, 0)/rgb(9, 9, 9)/normal
ARIA reflectsbutton/Save/nullbutton/Save/nullbutton/null/undefined
formDisabledCallbacktruenonenone
a clonable root is cloned<i>x</i>no root<i>x</i>
template content is inertnothrows:TypeErrorno
document.textContentnull/HTMLnull/HTML/HTML
Element.moveBefore1/0/keptmissingmissing
Document.parseHTMLUnsafe<i>in</i>missingmissing
dialog.show and closetrue/false/okmissingtrue/false/ok
popover methodsauto/true/falsemissingmissing
CommandEventshow-popover/truemissingmissing
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)throws:TypeErrorrgb(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
resolved font size32px2em16px
structuredCloneyesnono
fetchyesnoyes
WebSocketyesyesno
Workeryesnono
URL.createObjectURLyesnoyes
alertyesyesno
MathMLElementyesnono
SVGGeometryElementyesnoyes
showPopoveryesnono
dialog.showModalyesnoyes

Differences from Chrome

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

Legacy or superseded by a modern API that is implemented.

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

Refused by name: the modern interface name is accepted, and the HTML4 alias is answered with the constructor to use instead.

FeatureChromeesdev
createEvent refuses the HTML4 aliasescreatedNotSupportedError

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 layout: there is no box model, so there is nothing to measure or scroll.

FeatureChromeesdev
getBoundingClientRect measuresmeasuredzero
offsetWidth measuresmeasuredzero

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

FeatureChromeesdev
Element.animate (WAAPI)yesno
document.startViewTransitionyesno

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
XMLHttpRequestyesno
Imageyesno
canvas.getContextcontextmissing
iframe.contentWindowwindownull
Last updated on
Edit this page