DOM

Living Standard — Last Updated

Participate:
GitHub whatwg/dom (new issue, open issues)
Chat on Matrix
Commits:
GitHub whatwg/dom/commits
Snapshot as of this commit
@thedomstandard
Tests:
web-platform-tests dom/ (ongoing work)
Translations (non-normative):
日本語
简体中文
한국어

Abstract

DOM defines a platform-neutral model for events, aborting activities, and node trees.

1. Infrastructure

This specification depends on the Infra Standard. [INFRA]

Some of the terms used in this specification are defined in Encoding, Selectors, Web IDL, XML, and Namespaces in XML. [ENCODING] [SELECTORS4] [WEBIDL] [XML] [XML-NAMES]

When extensions are needed, the DOM Standard can be updated accordingly, or a new standard can be written that hooks into the provided extensibility hooks for applicable specifications.

1.1. Trees

A tree is a finite hierarchical tree structure. In tree order is preorder, depth-first traversal of a tree.

An object that participates in a tree has a parent, which is either null or an object, and has children, which is an ordered set of objects. An object A whose parent is object B is a child of B.

The root of an object is itself, if its parent is null, or else it is the root of its parent. The root of a tree is any object participating in that tree whose parent is null.

An object A is called a descendant of an object B, if either A is a child of B or A is a child of an object C that is a descendant of B.

An inclusive descendant is an object or one of its descendants.

An object A is called an ancestor of an object B if and only if B is a descendant of A.

An inclusive ancestor is an object or one of its ancestors.

An object A is called a sibling of an object B, if and only if B and A share the same non-null parent.

An inclusive sibling is an object or one of its siblings.

An object A is preceding an object B if A and B are in the same tree and A comes before B in tree order.

An object A is following an object B if A and B are in the same tree and A comes after B in tree order.

The first child of an object is its first child or null if it has no children.

The last child of an object is its last child or null if it has no children.

The previous sibling of an object is its first preceding sibling or null if it has no preceding sibling.

The next sibling of an object is its first following sibling or null if it has no following sibling.

The index of an object is its number of preceding siblings, or 0 if it has none.

1.2. Ordered sets

The ordered set parser takes a string input and then runs these steps:

  1. Let inputTokens be the result of splitting input on ASCII whitespace.

  2. Let tokens be a new ordered set.

  3. For each token of inputTokens, append token to tokens.

  4. Return tokens.

The ordered set serializer takes a set and returns the concatenation of set using U+0020 SPACE.

1.3. Selectors

To scope-match a selectors string selectors against a node, run these steps:

  1. Let s be the result of parse a selector selectors. [SELECTORS4]

  2. If s is failure, then throw a "SyntaxError" DOMException.

  3. Return the result of match a selector against a tree with s and node’s root using scoping root node. [SELECTORS4].

Support for namespaces within selectors is not planned and will not be added.

1.4. Name validation

A string is a valid namespace prefix if its length is at least 1 and it does not contain ASCII whitespace, U+0000 NULL, U+002F (/), or U+003E (>).

A string is a valid attribute local name if its length is at least 1 and it does not contain ASCII whitespace, U+0000 NULL, U+002F (/), U+003D (=), or U+003E (>).

A string name is a valid element local name if the following steps return true:

  1. If name’s length is 0, then return false.

  2. If name’s 0th code point is an ASCII alpha, then:

    1. If name contains ASCII whitespace, U+0000 NULL, U+002F (/), or U+003E (>), then return false.

    2. Return true.

  3. If name’s 0th code point is not U+003A (:), U+005F (_), or in the range U+0080 to U+10FFFF, inclusive, then return false.

  4. If name’s subsequent code points, if any, are not ASCII alphas, ASCII digits, U+002D (-), U+002E (.), U+003A (:), U+005F (_), or in the range U+0080 to U+10FFFF, inclusive, then return false.

  5. Return true.

This concept is used to validate element local names, when constructed by DOM APIs. The intention is to allow any name that is possible to construct using the HTML parser (the branch where the first code point is an ASCII alpha), plus some additional possibilities. For those additional possibilities, the ASCII range is restricted for historical reasons, but beyond ASCII anything is allowed.

The following JavaScript-compatible regular expression is an implementation of valid element local name:

/^(?:[A-Za-z][^\0\t\n\f\r\u0020/>]*|[:_\u0080-\u{10FFFF}][A-Za-z0-9-.:_\u0080-\u{10FFFF}]*)$/u

A string is a valid doctype name if it does not contain ASCII whitespace, U+0000 NULL, or U+003E (>).

The empty string is a valid doctype name.

To validate and extract a namespace and qualifiedName, given a context:

  1. If namespace is the empty string, then set it to null.

  2. Let prefix be null.

  3. Let localName be qualifiedName.

  4. If qualifiedName contains a U+003A (:):

    1. Let splitResult be the result of running strictly split given qualifiedName and U+003A (:).

    2. Set prefix to splitResult[0].

    3. Set localName to splitResult[1].

    4. If prefix is not a valid namespace prefix, then throw an "InvalidCharacterError" DOMException.

  5. Assert: prefix is either null or a valid namespace prefix.

  6. If context is "attribute" and localName is not a valid attribute local name, then throw an "InvalidCharacterError" DOMException.

  7. If context is "element" and localName is not a valid element local name, then throw an "InvalidCharacterError" DOMException.

  8. If prefix is non-null and namespace is null, then throw a "NamespaceError" DOMException.

  9. If prefix is "xml" and namespace is not the XML namespace, then throw a "NamespaceError" DOMException.

  10. If either qualifiedName or prefix is "xmlns" and namespace is not the XMLNS namespace, then throw a "NamespaceError" DOMException.

  11. If namespace is the XMLNS namespace and neither qualifiedName nor prefix is "xmlns", then throw a "NamespaceError" DOMException.

  12. Return (namespace, prefix, localName).

Various APIs in this specification used to validate namespace prefixes, attribute local names, element local names, and doctype names more strictly. This was done in a way that aligned with various XML-related specifications. (Although not all rules from the those specifications were enforced.)

This was found to be annoying for web developers, especially since it meant there were some names that could be created by the HTML parser, but not by DOM APIs. So, the validations have been loosened to just those described above.

2. Events

2.1. Introduction to "DOM Events"

Throughout the web platform events are dispatched to objects to signal an occurrence, such as network activity or user interaction. These objects implement the EventTarget interface and can therefore add event listeners to observe events by calling addEventListener():

obj.addEventListener("load", imgFetched)

function imgFetched(ev) {
  // great success}

Event listeners can be removed by utilizing the removeEventListener() method, passing the same arguments.

Alternatively, event listeners can be removed by passing an AbortSignal to addEventListener() and calling abort() on the controller owning the signal.

Events are objects too and implement the Event interface (or a derived interface). In the example above ev is the event. ev is passed as an argument to the event listener’s callback (typically a JavaScript Function as shown above). Event listeners key off the event’s type attribute value ("load" in the above example). The event’s target attribute value returns the object to which the event was dispatched (obj above).

Although events are typically dispatched by the user agent as the result of user interaction or the completion of some task, applications can dispatch events themselves by using what are commonly known as synthetic events:

// add an appropriate event listener
obj.addEventListener("cat", function(e) { process(e.detail) })

// create and dispatch the event
var event = new CustomEvent("cat", {"detail":{"hazcheeseburger":true}})
obj.dispatchEvent(event)

Apart from signaling, events are sometimes also used to let an application control what happens next in an operation. For instance as part of form submission an event whose type attribute value is "submit" is dispatched. If this event’s preventDefault() method is invoked, form submission will be terminated. Applications who wish to make use of this functionality through events dispatched by the application (synthetic events) can make use of the return value of the dispatchEvent() method:

if(obj.dispatchEvent(event)) {
  // event was not canceled, time for some magic}

When an event is dispatched to an object that participates in a tree (e.g., an element), it can reach event listeners on that object’s ancestors too. Effectively, all the object’s inclusive ancestor event listeners whose capture is true are invoked, in tree order. And then, if event’s bubbles is true, all the object’s inclusive ancestor event listeners whose capture is false are invoked, now in reverse tree order.

Let’s look at an example of how events work in a tree:

<!doctype html>
<html>
 <head>
  <title>Boring example</title>
 </head>
 <body>
  <p>Hello <span id=x>world</span>!</p>
  <script>
   function test(e) {
     debug(e.target, e.currentTarget, e.eventPhase)
   }
   document.addEventListener("hey", test, {capture: true})
   document.body.addEventListener("hey", test)
   var ev = new Event("hey", {bubbles:true})
   document.getElementById("x").dispatchEvent(ev)
  </script>
 </body>
</html>

The debug function will be invoked twice. Each time the event’s target attribute value will be the span element. The first time currentTarget attribute’s value will be the document, the second time the body element. eventPhase attribute’s value switches from CAPTURING_PHASE to BUBBLING_PHASE. If an event listener was registered for the span element, eventPhase attribute’s value would have been AT_TARGET.

2.2. Interface Event

[Exposed=*]
interface Event {
  constructor(DOMString type, optional EventInit eventInitDict = {});

  readonly attribute DOMString type;
  readonly attribute EventTarget? target;
  readonly attribute EventTarget? srcElement; // legacy
  readonly attribute