Files
rust_browser/docs/DOM_Implementation_Checklist.md
Zachary D. Rowitsch 626a1c517c Implement document lifecycle events with code review fixes (§8.4, §7.1)
Add DOMContentLoaded, load, and readystatechange events with correct
readyState transitions (loading→interactive→complete). Includes Window
as a first-class event target, body onload spec quirk, and idempotency
guards to prevent double-firing. Code review hardened the API surface
by enforcing forward-only state transitions, eliminating a redundant
wrapper function, and requesting a redraw after load handler DOM mutations.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 00:38:46 -04:00

18 KiB

DOM Implementation Checklist

Checked items mean the feature is implemented end-to-end: internal Rust API exists, JS binding is exposed (where applicable), and behavior is correct. Partial support is left unchecked and called out inline.

Phase 0: Architecture & Infrastructure

  • Arena-based DOM tree using NodeId indices (no lifetimes in cross-crate APIs)
  • Document dirty flag for mutation tracking
  • DOM conformance test harness (WPT DOM suite integration)
  • IDL attribute reflection framework (auto-generate JS getters/setters from IDL)

Phase 1: Node Types

  • Document node
  • Element node
  • Text node (CharacterData)
  • Comment node (CharacterData)
  • DocumentFragment
    • Current state: not implemented; needed for template contents, createDocumentFragment(), and Range operations.
  • DocumentType (doctype node)
  • ProcessingInstruction
  • CDATASection (XML only; low priority)
  • Attr as a node type (attributes are stored as key-value pairs on ElementData, not as separate nodes)

Phase 2: Node Interface

2.1 Properties

  • nodeType (internal — used by the engine)
    • Current state: Rust-level only; not exposed to JS as a numeric constant.
  • nodeName / nodeValue
  • ownerDocument
  • parentNode / parentElement
    • Current state: Rust-level parent() / parentElement() exist; not JS-exposed.
  • childNodes (internal iteration via children())
    • Current state: Rust-level only; not returned as a live NodeList.
  • firstChild / lastChild
    • Current state: first_child() exists in Rust; lastChild is missing. Neither JS-exposed.
  • nextSibling / previousSibling
    • Current state: next_sibling() exists in Rust; previousSibling is missing. Neither JS-exposed.
  • textContent (full Node-level semantics)
    • Current state: getter/setter works on Elements via JS; full Node-level semantics (null for Document, concatenation for DocumentFragment) not complete.
  • isConnected
  • baseURI

2.2 Node Constants

  • Node.ELEMENT_NODE (1), Node.TEXT_NODE (3), Node.COMMENT_NODE (8), etc.

2.3 Mutation Methods

  • appendChild(child) (Rust + JS)
  • removeChild(child) (Rust + JS)
  • insertBefore(newNode, referenceNode)
  • replaceChild(newChild, oldChild)
  • set_text_content() (replaces all children with text; Rust-level, JS setter on Element)

2.4 Query & Comparison Methods

  • cloneNode(deep)
  • contains(node)
  • hasChildNodes()
  • compareDocumentPosition(other)
  • isEqualNode(other) / isSameNode(other)
  • normalize() (merge adjacent Text nodes)
  • lookupPrefix() / lookupNamespaceURI() / isDefaultNamespace() (XML namespace; low priority)

Phase 3: Document Interface

3.1 Node Creation

  • document.createElement(tagName)
  • document.createTextNode(data) (Rust-level create_text())
    • Current state: Rust-level only; not JS-exposed.
  • document.createComment(data) (Rust-level create_comment())
    • Current state: Rust-level only; not JS-exposed.
  • document.createDocumentFragment()
  • document.createEvent(type) (legacy but widely used)
  • document.createTreeWalker(root, whatToShow, filter)
  • document.createNodeIterator(root, whatToShow, filter)
  • document.createRange()
  • document.importNode(node, deep) / document.adoptNode(node)

3.2 Query Methods

  • document.getElementById(id) (Rust + JS)
  • document.getElementsByTagName(tagName) (JS binding)
    • Current state: Rust-level implementation exists; not exposed to JS.
  • document.getElementsByClassName(className) (JS binding)
    • Current state: Rust-level implementation exists; not exposed to JS.
  • document.getElementsByName(name)
  • document.querySelector(selectors)
  • document.querySelectorAll(selectors)
    • Current state: selector matching engine exists in the selectors crate; not wired to JS query APIs.

3.3 Document Properties

  • document.documentElement (root <html> element)
  • document.head / document.body
  • document.title (get/set)
  • document.URL / document.documentURI
  • document.domain (deprecated but commonly accessed)
  • document.referrer
  • document.cookie (get/set)
  • document.readyState
  • document.characterSet / document.charset
  • document.contentType
  • document.compatMode (quirks vs standards)
  • document.doctype
  • document.activeElement
  • document.visibilityState / document.hidden

3.4 Document Lifecycle Events

  • DOMContentLoaded event
  • load event
  • readystatechange event
  • visibilitychange event

Phase 4: Element Interface

4.1 Core Properties

  • element.id (get; JS-exposed)
  • element.tagName (JS-exposed)
  • element.className (JS-exposed)
  • element.classList (returns DOMTokenList)
  • element.slot
  • element.localName / element.namespaceURI / element.prefix

4.2 Attribute Methods

  • element.getAttribute(name) (internal storage; JS-exposed as property access)
    • Current state: attributes stored as Vec of name-value pairs; JS reads attributes via property access, not a dedicated getAttribute() call.
  • element.setAttribute(name, value) (Rust-level)
    • Current state: Rust-level only; not exposed as a JS method.
  • element.getAttribute(name) (JS method)
  • element.setAttribute(name, value) (JS method)
  • element.removeAttribute(name)
  • element.hasAttribute(name)
  • element.toggleAttribute(name, force)
  • element.getAttributeNames()
  • element.attributes (returns NamedNodeMap)
  • element.dataset (data-* attributes as DOMStringMap)

4.3 Content Properties

  • element.textContent (getter/setter; JS-exposed)
  • element.innerHTML (getter/setter; JS-exposed)
    • Current state: wired to fragment parse/serialize; not fully spec-compliant context-sensitive parsing.
  • element.outerHTML (getter/setter)
  • element.innerText (getter/setter; layout-aware)
  • element.insertAdjacentHTML(position, text)
  • element.insertAdjacentElement(position, element)
  • element.insertAdjacentText(position, text)

4.4 Traversal Properties

  • element.children (returns live HTMLCollection of child elements)
  • element.childElementCount
  • element.firstElementChild / element.lastElementChild
  • element.nextElementSibling / element.previousElementSibling
    • Current state: Rust-level element_siblings() exists for CSS selector matching; not JS-exposed.
  • element.closest(selectors)
  • element.matches(selectors)
    • Current state: selector matching logic exists internally; not JS-exposed.

4.5 Query Methods (on Element)

  • element.querySelector(selectors)
  • element.querySelectorAll(selectors)
  • element.getElementsByTagName(tagName)
  • element.getElementsByClassName(className)

4.6 Geometry & Scroll

  • element.getBoundingClientRect()DOMRect
  • element.getClientRects()DOMRectList
  • element.clientWidth / element.clientHeight
  • element.clientTop / element.clientLeft
  • element.scrollWidth / element.scrollHeight
  • element.scrollTop / element.scrollLeft (get/set)
  • element.scrollIntoView()
  • element.offsetWidth / element.offsetHeight
  • element.offsetTop / element.offsetLeft
  • element.offsetParent

4.7 Focus & Interaction

  • element.focus() / element.blur()
  • element.click()
  • element.tabIndex

Phase 5: DOM Collections

  • NodeList (live and static variants)
    • Live: returned by childNodes, getElementsByTagName, getElementsByClassName
    • Static: returned by querySelectorAll
    • Required methods: item(index), length, forEach(), entries(), keys(), values()
  • HTMLCollection (live, returned by children, getElementsByTagName on Element)
    • Required methods: item(index), namedItem(name), length
  • DOMTokenList (for classList, relList, sandbox, etc.)
    • Required methods: add(), remove(), toggle(), contains(), replace(), item(), length, value, forEach()
  • NamedNodeMap (for element.attributes)
    • Required methods: getNamedItem(), setNamedItem(), removeNamedItem(), item(), length

Phase 6: Events

6.1 EventTarget Interface

  • addEventListener(type, listener, options/useCapture)
  • removeEventListener(type, listener)
  • dispatchEvent(event) (programmatic dispatch)

6.2 Event Interface

  • event.type
  • event.target / event.currentTarget
  • event.bubbles / event.cancelable
  • event.defaultPrevented
  • event.eventPhase
  • event.preventDefault()
  • event.stopPropagation()
  • event.stopImmediatePropagation()
  • event.composed / event.composedPath()
  • event.isTrusted
  • event.timeStamp

6.3 Event Dispatch Algorithm

  • Target phase
  • Bubble phase
    • Current state: implemented for click events.
  • Capture phase
  • Correct event path construction (including shadow DOM composed path)
  • Passive event listeners ({ passive: true })
  • once option ({ once: true })
  • Event listener signal option (AbortSignal integration)

6.4 Event Constructors

  • new Event(type, options)
  • new CustomEvent(type, options) with detail property
  • new MouseEvent(type, options)
  • new KeyboardEvent(type, options)
  • new FocusEvent(type, options)
  • new InputEvent(type, options)
  • new WheelEvent(type, options)
  • new PointerEvent(type, options)

6.5 Event Types

  • click
  • Mouse: mousedown, mouseup, mousemove, mouseenter, mouseleave, mouseover, mouseout, dblclick, contextmenu
  • Keyboard: keydown, keyup, keypress (deprecated)
  • Focus: focus, blur, focusin, focusout
  • Input: input, change, beforeinput
  • Form: submit, reset, invalid
  • Drag: dragstart, drag, dragend, dragenter, dragleave, dragover, drop
  • Touch: touchstart, touchmove, touchend, touchcancel
  • Pointer: pointerdown, pointerup, pointermove, pointerenter, pointerleave, pointerover, pointerout, pointercancel, gotpointercapture, lostpointercapture
  • Scroll: scroll, scrollend
  • Resize: resize
  • Clipboard: copy, cut, paste
  • Animation: animationstart, animationend, animationiteration, transitionend

Phase 7: DOM Traversal

  • TreeWalker interface
    • createTreeWalker(root, whatToShow, filter)
    • Methods: parentNode(), firstChild(), lastChild(), previousSibling(), nextSibling(), previousNode(), nextNode()
    • whatToShow bitmask filtering
  • NodeIterator interface
    • createNodeIterator(root, whatToShow, filter)
    • Methods: nextNode(), previousNode(), detach()
  • Internal tree iteration (Rust-level TreeIterator for pre-order traversal)
    • Current state: used by the engine for style/layout; not JS-exposed.

Phase 8: Ranges

  • Range interface
    • Construction: document.createRange(), new Range()
    • Boundary: setStart(), setEnd(), setStartBefore(), setStartAfter(), setEndBefore(), setEndAfter()
    • Properties: startContainer, startOffset, endContainer, endOffset, collapsed, commonAncestorContainer
    • Comparison: compareBoundaryPoints(), comparePoint(), isPointInRange(), intersectsNode()
    • Content: cloneContents(), extractContents(), deleteContents(), insertNode(), surroundContents()
    • Utility: cloneRange(), detach(), toString()
    • createContextualFragment(html)
  • StaticRange interface
  • AbstractRange base interface

Phase 9: Selection API

  • window.getSelection()Selection
  • Selection interface
    • Properties: anchorNode, anchorOffset, focusNode, focusOffset, isCollapsed, rangeCount, type
    • Methods: getRangeAt(), addRange(), removeRange(), removeAllRanges(), collapse(), collapseToStart(), collapseToEnd(), extend(), selectAllChildren(), deleteFromDocument(), containsNode(), toString()
  • Input selection: selectionStart, selectionEnd, selectionDirection on input/textarea
  • select event

Phase 10: MutationObserver

  • new MutationObserver(callback)
  • .observe(target, options) — options: childList, attributes, characterData, subtree, attributeFilter, attributeOldValue, characterDataOldValue
  • .disconnect()
  • .takeRecords()
  • MutationRecord interface
    • Properties: type, target, addedNodes, removedNodes, previousSibling, nextSibling, attributeName, attributeNamespace, oldValue

Phase 11: CSSOM (CSS Object Model)

11.1 Inline Style Access

  • element.styleCSSStyleDeclaration
    • Property access: element.style.color, element.style.fontSize, etc.
    • Methods: getPropertyValue(), setProperty(), removeProperty(), getPropertyPriority()
    • element.style.cssText (get/set)
    • element.style.length / element.style.item(index)

11.2 Computed Style

  • window.getComputedStyle(element, pseudoElt)CSSStyleDeclaration
    • Current state: computed styles exist in the style crate; not exposed to JS.

11.3 Stylesheet Access

  • document.styleSheetsStyleSheetList
  • CSSStyleSheet interface
    • .cssRules / .insertRule() / .deleteRule()
  • CSSRule / CSSStyleRule / CSSMediaRule / CSSImportRule interfaces

Phase 12: DOM Parsing & Serialization

  • DOMParser
    • new DOMParser()
    • .parseFromString(str, type) — types: text/html, text/xml, application/xml, application/xhtml+xml, image/svg+xml
  • XMLSerializer
    • new XMLSerializer()
    • .serializeToString(node)
  • innerHTML setter (uses HTML parser for fragment parsing)
    • Current state: basic fragment parse/serialize; not fully spec-compliant.
  • innerHTML getter (serializes child nodes to HTML string)

Phase 13: HTML-Specific Element Interfaces

13.1 HTMLElement Base

  • HTMLElement interface (extends Element)
    • Properties: title, lang, dir, hidden, draggable, contentEditable, isContentEditable, spellcheck, tabIndex
    • Style: .style property → CSSStyleDeclaration
    • Data: .datasetDOMStringMap
    • Interaction: .click(), .focus(), .blur()
    • Offset: .offsetTop, .offsetLeft, .offsetWidth, .offsetHeight, .offsetParent
    • Scroll: .scrollTop, .scrollLeft, .scrollWidth, .scrollHeight

13.2 Specific Element Interfaces

  • HTMLAnchorElementhref, target, rel, download, origin, protocol, hostname, pathname, etc.
  • HTMLImageElementsrc, alt, width, height, naturalWidth, naturalHeight, complete, currentSrc, decode()
  • HTMLInputElementvalue, type, name, checked, disabled, readOnly, placeholder, required, validity, checkValidity(), setCustomValidity()
  • HTMLSelectElementvalue, selectedIndex, options, selectedOptions, multiple, add(), remove()
  • HTMLTextAreaElementvalue, rows, cols, selectionStart, selectionEnd, select()
  • HTMLFormElementelements, action, method, submit(), reset(), checkValidity()
  • HTMLButtonElementtype, value, disabled, form
  • HTMLCanvasElementgetContext(), width, height, toDataURL(), toBlob()
  • HTMLMediaElementsrc, play(), pause(), currentTime, duration, paused, volume, muted
  • HTMLVideoElementvideoWidth, videoHeight, poster
  • HTMLTableElementrows, tBodies, tHead, tFoot, caption, insertRow(), deleteRow(), createTHead(), createTBody(), createTFoot(), createCaption()
  • HTMLScriptElementsrc, type, async, defer, text
  • HTMLStyleElementsheet
  • HTMLLinkElementhref, rel, type, sheet
  • HTMLTemplateElementcontent (DocumentFragment)

Phase 14: AbortController / AbortSignal

  • new AbortController()
  • AbortController.prototype.signalAbortSignal
  • AbortController.prototype.abort(reason)
  • AbortSignal.prototype.aborted
  • AbortSignal.prototype.reason
  • AbortSignal.prototype.onabort / addEventListener('abort', ...)
  • AbortSignal.abort(reason) (static)
  • AbortSignal.timeout(ms) (static)
  • Integration with fetch(), event listeners, and other abortable APIs

Phase 15: Intersection & Resize Observers

  • IntersectionObserver
    • new IntersectionObserver(callback, options)
    • .observe(target), .unobserve(target), .disconnect(), .takeRecords()
    • IntersectionObserverEntrytarget, isIntersecting, intersectionRatio, intersectionRect, boundingClientRect, rootBounds, time
  • ResizeObserver
    • new ResizeObserver(callback)
    • .observe(target, options), .unobserve(target), .disconnect()
    • ResizeObserverEntrytarget, contentRect, borderBoxSize, contentBoxSize

Phase 16: Conformance Exit Criteria

  • All Node types per DOM Living Standard implemented
  • DOM mutation methods complete and correct (appendChild, insertBefore, replaceChild, removeChild, cloneNode)
  • Query APIs wired to JS (querySelector, querySelectorAll, getElementById, getElementsByTagName, getElementsByClassName)
  • DOM collections implemented (NodeList, HTMLCollection, DOMTokenList)
  • Event dispatch algorithm spec-compliant (capture → target → bubble)
  • CSSOM basics exposed to JS (element.style, getComputedStyle)
  • Pass WPT DOM test suite at target threshold
  • No crashers: malformed DOM operations must not crash the engine
  • Publish DOM conformance report with pass rates and remaining gaps