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 EventTarget? currentTarget;
  sequence<EventTarget> composedPath();

  const unsigned short NONE = 0;
  const unsigned short CAPTURING_PHASE = 1;
  const unsigned short AT_TARGET = 2;
  const unsigned short BUBBLING_PHASE = 3;
  readonly attribute unsigned short eventPhase;

  undefined stopPropagation();
           attribute boolean cancelBubble; // legacy alias of .stopPropagation()
  undefined stopImmediatePropagation();

  readonly attribute boolean bubbles;
  readonly attribute boolean cancelable;
           attribute boolean returnValue;  // legacy
  undefined preventDefault();
  readonly attribute boolean defaultPrevented;
  readonly attribute boolean composed;

  [LegacyUnforgeable] readonly attribute boolean isTrusted;
  readonly attribute DOMHighResTimeStamp timeStamp;

  undefined initEvent(DOMString type, optional boolean bubbles = false, optional boolean cancelable = false); // legacy
};

dictionary EventInit {
  boolean bubbles = false;
  boolean cancelable = false;
  boolean composed = false;
};

An Event object is simply named an event. It allows for signaling that something has occurred, e.g., that an image has completed downloading.

A potential event target is null or an EventTarget object.

An event has an associated target (a potential event target). Unless stated otherwise it is null.

An event has an associated relatedTarget (a potential event target). Unless stated otherwise it is null.

Other specifications use relatedTarget to define a relatedTarget attribute. [UIEVENTS]

An event has an associated touch target list (a list of zero or more potential event targets). Unless stated otherwise it is the empty list.

The touch target list is for the exclusive use of defining the TouchEvent interface and related interfaces. [TOUCH-EVENTS]

An event has an associated path. A path is a list of structs. Each struct consists of an invocation target (an EventTarget object), an invocation-target-in-shadow-tree (a boolean), a shadow-adjusted target (a potential event target), a relatedTarget (a potential event target), a touch target list (a list of potential event targets), a root-of-closed-tree (a boolean), and a slot-in-closed-tree (a boolean). A path is initially the empty list.

event = new Event(type [, eventInitDict])
Returns a new event whose type attribute value is set to type. The eventInitDict argument allows for setting the bubbles and cancelable attributes via object members of the same name.
event . type
Returns the type of event, e.g. "click", "hashchange", or "submit".
event . target
Returns the object to which event is dispatched (its target).
event . currentTarget
Returns the object whose event listener’s callback is currently being invoked.
event . composedPath()
Returns the invocation target objects of event’s path (objects on which listeners will be invoked), except for any nodes in shadow trees of which the shadow root’s mode is "closed" that are not reachable from event’s currentTarget.
event . eventPhase
Returns the event’s phase, which is one of NONE, CAPTURING_PHASE, AT_TARGET, and BUBBLING_PHASE.
event . stopPropagation()
When dispatched in a tree, invoking this method prevents event from reaching any objects other than the current object.
event . stopImmediatePropagation()
Invoking this method prevents event from reaching any registered event listeners after the current one finishes running and, when dispatched in a tree, also prevents event from reaching any other objects.
event . bubbles
Returns true or false depending on how event was initialized. True if event goes through its target’s ancestors in reverse tree order; otherwise false.
event . cancelable
Returns true or false depending on how event was initialized. Its return value does not always carry meaning, but true can indicate that part of the operation during which event was dispatched, can be canceled by invoking the preventDefault() method.
event . preventDefault()
If invoked when the cancelable attribute value is true, and while executing a listener for the event with passive set to false, signals to the operation that caused event to be dispatched that it needs to be canceled.
event . defaultPrevented
Returns true if preventDefault() was invoked successfully to indicate cancelation; otherwise false.
event . composed
Returns true or false depending on how event was initialized. True if event invokes listeners past a ShadowRoot node that is the root of its target; otherwise false.
event . isTrusted
Returns true if event was dispatched by the user agent, and false otherwise.
event . timeStamp
Returns the event’s timestamp as the number of milliseconds measured relative to the occurrence.

The type attribute must return the value it was initialized to. When an event is created the attribute must be initialized to the empty string.

The target getter steps are to return this’s target.

The srcElement getter steps are to return this’s target.

The currentTarget attribute must return the value it was initialized to. When an event is created the attribute must be initialized to null.

The composedPath() method steps are:

  1. Let composedPath be an empty list.

  2. Let path be this’s path.

  3. If path is empty, then return composedPath.

  4. Let currentTarget be this’s currentTarget attribute value.

  5. Assert: currentTarget is an EventTarget object.

  6. Append currentTarget to composedPath.

  7. Let currentTargetIndex be 0.

  8. Let currentTargetHiddenSubtreeLevel be 0.

  9. Let index be path’s size − 1.

  10. While index is greater than or equal to 0:

    1. If path[index]'s root-of-closed-tree is true, then increase currentTargetHiddenSubtreeLevel by 1.

    2. If path[index]'s invocation target is currentTarget, then set currentTargetIndex to index and break.

    3. If path[index]'s slot-in-closed-tree is true, then decrease currentTargetHiddenSubtreeLevel by 1.

    4. Decrease index by 1.

  11. Let currentHiddenLevel and maxHiddenLevel be currentTargetHiddenSubtreeLevel.

  12. Set index to currentTargetIndex − 1.

  13. While index is greater than or equal to 0:

    1. If path[index]'s root-of-closed-tree is true, then increase currentHiddenLevel by 1.

    2. If currentHiddenLevel is less than or equal to maxHiddenLevel, then prepend path[index]'s invocation target to composedPath.

    3. If path[index]'s slot-in-closed-tree is true:

      1. Decrease currentHiddenLevel by 1.

      2. If currentHiddenLevel is less than maxHiddenLevel, then set maxHiddenLevel to currentHiddenLevel.

    4. Decrease index by 1.

  14. Set currentHiddenLevel and maxHiddenLevel to currentTargetHiddenSubtreeLevel.

  15. Set index to currentTargetIndex + 1.

  16. While index is less than path’s size:

    1. If path[index]'s slot-in-closed-tree is true, then increase currentHiddenLevel by 1.

    2. If currentHiddenLevel is less than or equal to maxHiddenLevel, then append path[index]'s invocation target to composedPath.

    3. If path[index]'s root-of-closed-tree is true:

      1. Decrease currentHiddenLevel by 1.

      2. If currentHiddenLevel is less than maxHiddenLevel, then set maxHiddenLevel to currentHiddenLevel.

    4. Increase index by 1.

  17. Return composedPath.

The eventPhase attribute must return the value it was initialized to, which must be one of the following:

NONE (numeric value 0)
Events not currently dispatched are in this phase.
CAPTURING_PHASE (numeric value 1)
When an event is dispatched to an object that participates in a tree it will be in this phase before it reaches its target.
AT_TARGET (numeric value 2)
When an event is dispatched it will be in this phase on its target.
BUBBLING_PHASE (numeric value 3)
When an event is dispatched to an object that participates in a tree it will be in this phase after it reaches its target.

Initially the attribute must be initialized to NONE.


Each event has the following associated flags that are all initially unset:

The stopPropagation() method steps are to set this’s stop propagation flag.

The cancelBubble getter steps are to return true if this’s stop propagation flag is set; otherwise false.

The cancelBubble setter steps are to set this’s stop propagation flag if the given value is true; otherwise do nothing.

The stopImmediatePropagation() method steps are to set this’s stop propagation flag and this’s stop immediate propagation flag.

The bubbles and cancelable attributes must return the values they were initialized to.

To set the canceled flag, given an event event, if event’s cancelable attribute value is true and event’s in passive listener flag is unset, then set event’s canceled flag, and do nothing otherwise.

The returnValue getter steps are to return false if this’s canceled flag is set; otherwise true.

The returnValue setter steps are to set the canceled flag with this if the given value is false; otherwise do nothing.

The preventDefault() method steps are to set the canceled flag with this.

There are scenarios where invoking preventDefault() has no effect. User agents are encouraged to log the precise cause in a developer console, to aid debugging.

The defaultPrevented getter steps are to return true if this’s canceled flag is set; otherwise false.

The composed getter steps are to return true if this’s composed flag is set; otherwise false.


The isTrusted attribute must return the value it was initialized to. When an event is created the attribute must be initialized to false.

isTrusted is a convenience that indicates whether an event is dispatched by the user agent (as opposed to using dispatchEvent()). The sole legacy exception is click(), which causes the user agent to dispatch an event whose isTrusted attribute is initialized to false.

The timeStamp attribute must return the value it was initialized to.


To initialize an event, with type, bubbles, and cancelable, run these steps:

  1. Set event’s initialized flag.

  2. Unset event’s stop propagation flag, stop immediate propagation flag, and canceled flag.

  3. Set event’s isTrusted attribute to false.

  4. Set event’s target to null.

  5. Set event’s type attribute to type.

  6. Set event’s bubbles attribute to bubbles.

  7. Set event’s cancelable attribute to cancelable.

The initEvent(type, bubbles, cancelable) method steps are:

  1. If this’s dispatch flag is set, then return.

  2. Initialize this with type, bubbles, and cancelable.

initEvent() is redundant with event constructors and incapable of setting composed. It has to be supported for legacy content.

2.3. Legacy extensions to the Window interface

partial interface Window {
  [Replaceable] readonly attribute (Event or undefined) event; // legacy
};

Each Window object has an associated current event (undefined or an Event object). Unless stated otherwise it is undefined.

The event getter steps are to return this’s current event.

Web developers are strongly encouraged to instead rely on the Event object passed to event listeners, as that will result in more portable code. This attribute is not available in workers or worklets, and is inaccurate for events dispatched in shadow trees.

2.4. Interface CustomEvent

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

  readonly attribute any detail;

  undefined initCustomEvent(DOMString type, optional boolean bubbles = false, optional boolean cancelable = false, optional any detail = null); // legacy
};

dictionary CustomEventInit : EventInit {
  any detail = null;
};

Events using the CustomEvent interface can be used to carry custom data.

event = new CustomEvent(type [, eventInitDict])
Works analogously to the constructor for Event except that the eventInitDict argument now allows for setting the detail attribute too.
event . detail
Returns any custom data event was created with. Typically used for synthetic events.

The detail attribute must return the value it was initialized to.

The initCustomEvent(type, bubbles, cancelable, detail) method steps are:

  1. If this’s dispatch flag is set, then return.

  2. Initialize this with type, bubbles, and cancelable.

  3. Set this’s detail attribute to detail.

2.5. Constructing events

Specifications may define event constructing steps for all or some events. The algorithm is passed an event event and an EventInit eventInitDict as indicated in the inner event creation steps.

This construct can be used by Event subclasses that have a more complex structure than a simple 1:1 mapping between their initializing dictionary members and IDL attributes.

When a constructor of the Event interface, or of an interface that inherits from the Event interface, is invoked, these steps must be run, given the arguments type and eventInitDict:

  1. Let event be the result of running the inner event creation steps with this interface, null, now, and eventInitDict.

  2. Initialize event’s type attribute to type.

  3. Return event.

To create an event using eventInterface, which must be either Event or an interface that inherits from it, and optionally given a realm realm, run these steps:

  1. If realm is not given, then set it to null.

  2. Let dictionary be the result of converting the JavaScript value undefined to the dictionary type accepted by eventInterface’s constructor. (This dictionary type will either be EventInit or a dictionary that inherits from it.)

    This does not work if members are required; see whatwg/dom#600.

  3. Let event be the result of running the inner event creation steps with eventInterface, realm, the time of the occurrence that the event is signaling, and dictionary.

    In macOS the time of the occurrence for input actions is available via the timestamp property of NSEvent objects.

  4. Initialize event’s isTrusted attribute to true.

  5. Return event.

Create an event is meant to be used by other specifications which need to separately create and dispatch events, instead of simply firing them. It ensures the event’s attributes are initialized to the correct defaults.

The inner event creation steps, given an eventInterface, realm, time, and dictionary, are as follows:

  1. Let event be the result of creating a new object using eventInterface. If realm is non-null, then use that realm; otherwise, use the default behavior defined in Web IDL.

    As of the time of this writing Web IDL does not yet define any default behavior; see whatwg/webidl#135.

  2. Set event’s initialized flag.

  3. Initialize event’s timeStamp attribute to the relative high resolution coarse time given time and event’s relevant global object.

  4. For each membervalue of dictionary, if event has an attribute whose identifier is member, then initialize that attribute to value.

  5. Run the event constructing steps with event and dictionary.

  6. Return event.

2.6. Defining event interfaces

In general, when defining a new interface that inherits from Event please always ask feedback from the WHATWG or the W3C WebApps WG community.

The CustomEvent interface can be used as starting point. However, do not introduce any init*Event() methods as they are redundant with constructors. Interfaces that inherit from the Event interface that have such a method only have it for historical reasons.

2.7. Interface EventTarget

[Exposed=*]
interface EventTarget {
  constructor();

  undefined addEventListener(DOMString type, EventListener? callback, optional (AddEventListenerOptions or boolean) options = {});
  undefined removeEventListener(DOMString type, EventListener? callback, optional (EventListenerOptions or boolean) options = {});
  boolean dispatchEvent(Event event);
};

callback interface EventListener {
  undefined handleEvent(Event event);
};

dictionary EventListenerOptions {
  boolean capture = false;
};

dictionary AddEventListenerOptions : EventListenerOptions {
  boolean passive;
  boolean once = false;
  AbortSignal signal;
};

An EventTarget object represents a target to which an event can be dispatched when something has occurred.

Each EventTarget object has an associated event listener list (a list of zero or more event listeners). It is initially the empty list.

An event listener can be used to observe a specific event and consists of:

Although callback is an EventListener object, an event listener is a broader concept as can be seen above.

Each EventTarget object also has an associated get the parent algorithm, which takes an event event, and returns an EventTarget object. Unless specified otherwise it returns null.

Nodes, shadow roots, and documents override the get the parent algorithm.

Each EventTarget object can have an associated activation behavior algorithm. The activation behavior algorithm is passed an event, as indicated in the dispatch algorithm.

This exists because user agents perform certain actions for certain EventTarget objects, e.g., the area element, in response to synthetic MouseEvent events whose type attribute is click. Web compatibility prevented it from being removed and it is now the enshrined way of defining an activation of something. [HTML]

Each EventTarget object that has activation behavior, can additionally have both (not either) a legacy-pre-activation behavior algorithm and a legacy-canceled-activation behavior algorithm.

These algorithms only exist for checkbox and radio input elements and are not to be used for anything else. [HTML]

target = new EventTarget();

Creates a new EventTarget object, which can be used by developers to dispatch and listen for events.

target . addEventListener(type, callback [, options])

Appends an event listener for events whose type attribute value is type. The callback argument sets the callback that will be invoked when the event is dispatched.

The options argument sets listener-specific options. For compatibility this can be a boolean, in which case the method behaves exactly as if the value was specified as options’s capture.

When set to true, options’s capture prevents callback from being invoked when the event’s eventPhase attribute value is BUBBLING_PHASE. When false (or not present), callback will not be invoked when event’s eventPhase attribute value is CAPTURING_PHASE. Either way, callback will be invoked if event’s eventPhase attribute value is AT_TARGET.

When set to true, options’s passive indicates that the callback will not cancel the event by invoking preventDefault(). This is used to enable performance optimizations described in § 2.8 Observing event listeners.

When set to true, options’s once indicates that the callback will only be invoked once after which the event listener will be removed.

If an AbortSignal is passed for options’s signal, then the event listener will be removed when signal is aborted.

The event listener is appended to target’s event listener list and is not appended if it has the same type, callback, and capture.

target . removeEventListener(type, callback [, options])

Removes the event listener in target’s event listener list with the same type, callback, and options.

target . dispatchEvent(event)

Dispatches a synthetic event event to target and returns true if either event’s cancelable attribute value is false or its preventDefault() method was not invoked; otherwise false.

To flatten options, run these steps:

  1. If options is a boolean, then return options.

  2. Return options["capture"].

To flatten more options, run these steps:

  1. Let capture be the result of flattening options.

  2. Let once be false.

  3. Let passive and signal be null.

  4. If options is a dictionary:

    1. Set once to options["once"].

    2. If options["passive"] exists, then set passive to options["passive"].

    3. If options["signal"] exists, then set signal to options["signal"].

  5. Return capture, passive, once, and signal.

The new EventTarget() constructor steps are to do nothing.

Because of the defaults stated elsewhere, the returned EventTarget’s get the parent algorithm will return null, and it will have no activation behavior, legacy-pre-activation behavior, or legacy-canceled-activation behavior.

In the future we could allow custom get the parent algorithms. Let us know if this would be useful for your programs. For now, all author-created EventTargets do not participate in a tree structure.

The default passive value, given an event type type and an EventTarget eventTarget, is determined as follows:

  1. Return true if all of the following are true:

  2. Return false.

To add an event listener, given an EventTarget object eventTarget and an event listener listener, run these steps:

  1. If eventTarget is a ServiceWorkerGlobalScope object, its service worker’s script resource’s has ever been evaluated flag is set, and listener’s type matches the type attribute value of any of the service worker events, then report a warning to the console that this might not give the expected results. [SERVICE-WORKERS]

  2. If listener’s signal is not null and is aborted, then return.

  3. If listener’s callback is null, then return.

  4. If listener’s passive is null, then set it to the default passive value given listener’s type and eventTarget.

  5. If eventTarget’s event listener list does not contain an event listener whose type is listener’s type, callback is listener’s callback, and capture is listener’s capture, then append listener to eventTarget’s event listener list.

  6. If listener’s signal is not null, then add the following abort steps to it:

    1. Remove an event listener with eventTarget and listener.

The add an event listener concept exists to ensure event handlers use the same code path. [HTML]

The addEventListener(type, callback, options) method steps are:

  1. Let capture, passive, once, and signal be the result of flattening more options.

  2. Add an event listener with this and an event listener whose type is type, callback is callback, capture is capture, passive is passive, once is once, and signal is signal.

To remove an event listener, given an EventTarget object eventTarget and an event listener listener, run these steps:

  1. If eventTarget is a ServiceWorkerGlobalScope object and its service worker’s set of event types to handle contains listener’s type, then report a warning to the console that this might not give the expected results. [SERVICE-WORKERS]

  2. Set listener’s removed to true and remove listener from eventTarget’s event listener list.

HTML needs this to define event handlers. [HTML]

To remove all event listeners, given an EventTarget object eventTarget, for each listener of eventTarget’s event listener list, remove an event listener with eventTarget and listener.

HTML needs this to define document.open(). [HTML]

The removeEventListener(type, callback, options) method steps are:

  1. Let capture be the result of flattening options.

  2. If this’s event listener list contains an event listener whose type is type, callback is callback, and capture is capture, then remove an event listener with this and that event listener.

The event listener list will not contain multiple event listeners with equal type, callback, and capture, as add an event listener prevents that.

The dispatchEvent(event) method steps are:

  1. If event’s dispatch flag is set, or if its initialized flag is not set, then throw an "InvalidStateError" DOMException.

  2. Initialize event’s isTrusted attribute to false.

  3. Return the result of dispatching event to this.

2.8. Observing event listeners

In general, developers do not expect the presence of an event listener to be observable. The impact of an event listener is determined by its callback. That is, a developer adding a no-op event listener would not expect it to have any side effects.

Unfortunately, some event APIs have been designed such that implementing them efficiently requires observing event listeners. This can make the presence of listeners observable in that even empty listeners can have a dramatic performance impact on the behavior of the application. For example, touch and wheel events which can be used to block asynchronous scrolling. In some cases this problem can be mitigated by specifying the event to be cancelable only when there is at least one non-passive listener. For example, non-passive TouchEvent listeners must block scrolling, but if all listeners are passive then scrolling can be allowed to start in parallel by making the TouchEvent uncancelable (so that calls to preventDefault() are ignored). So code dispatching an event is able to observe the absence of non-passive listeners, and use that to clear the cancelable property of the event being dispatched.

Ideally, any new event APIs are defined such that they do not need this property. (Use whatwg/dom for discussion.)

To legacy-obtain service worker fetch event listener callbacks given a ServiceWorkerGlobalScope global, run these steps. They return a list of EventListener objects.

  1. Let callbacks be « ».

  2. For each listener of global’s event listener list:

    1. If listener’s type is "fetch", and listener’s callback is not null, then append listener’s callback to callbacks.

  3. Return callbacks.

2.9. Dispatching events

To dispatch an event to a target, with an optional legacy target override flag and an optional legacyOutputDidListenersThrowFlag, run these steps:

  1. Set event’s dispatch flag.

  2. Let targetOverride be target, if legacy target override flag is not given, and target’s associated Document otherwise. [HTML]

    legacy target override flag is only used by HTML and only when target is a Window object.

  3. Let activationTarget be null.

  4. Let relatedTarget be the result of retargeting event’s relatedTarget against target.

  5. Let clearTargets be false.

  6. If target is not relatedTarget or target is event’s relatedTarget:

    1. Let touchTargets be a new list.

    2. For each touchTarget of event’s touch target list, append the result of retargeting touchTarget against target to touchTargets.

    3. Append to an event path with event, target, targetOverride, relatedTarget, touchTargets, and false.

    4. Let isActivationEvent be true, if event is a MouseEvent object and event’s type attribute is "click"; otherwise false.

    5. If isActivationEvent is true and target has activation behavior, then set activationTarget to target.

    6. Let slottable be target, if target is a slottable and is assigned, and null otherwise.

    7. Let slot-in-closed-tree be false.

    8. Let parent be the result of invoking target’s get the parent with event.

    9. While parent is non-null:

      1. If slottable is non-null:

        1. Assert: parent is a slot.

        2. Set slottable to null.

        3. If parent’s root is a shadow root whose mode is "closed", then set slot-in-closed-tree to true.

      2. If parent is a slottable and is assigned, then set slottable to parent.

      3. Let relatedTarget be the result of retargeting event’s relatedTarget against parent.

      4. Let touchTargets be a new list.

      5. For each touchTarget of event’s touch target list, append the result of retargeting touchTarget against parent to touchTargets.

      6. If parent is a Window object, or parent is a node and target’s root is a shadow-including inclusive ancestor of parent:

        1. If isActivationEvent is true, event’s bubbles attribute is true, activationTarget is null, and parent has activation behavior, then set activationTarget to parent.

        2. Append to an event path with event, parent, null, relatedTarget, touchTargets, and slot-in-closed-tree.

      7. Otherwise, if parent is relatedTarget, then set parent to null.

      8. Otherwise:

        1. Set target to parent.

        2. If isActivationEvent is true, activationTarget is null, and target has activation behavior, then set activationTarget to target.

        3. Append to an event path with event, parent, target, relatedTarget, touchTargets, and slot-in-closed-tree.

      9. If parent is non-null, then set parent to the result of invoking parent’s get the parent with event.

      10. Set slot-in-closed-tree to false.

    10. Let clearTargetsStruct be the last struct in event’s path whose shadow-adjusted target is non-null.

    11. If clearTargetsStruct’s shadow-adjusted target, clearTargetsStruct’s relatedTarget, or an EventTarget object in clearTargetsStruct’s touch target list is a node whose root is a shadow root: set clearTargets to true.

    12. If activationTarget is non-null and activationTarget has legacy-pre-activation behavior, then run activationTarget’s legacy-pre-activation behavior.

    13. For each struct of event’s path, in reverse order:

      1. If struct’s shadow-adjusted target is non-null, then set event’s eventPhase attribute to AT_TARGET.

      2. Otherwise, set event’s eventPhase attribute to CAPTURING_PHASE.

      3. Invoke with struct, event, "capturing", and legacyOutputDidListenersThrowFlag if given.

    14. For each struct of event’s path:

      1. If struct’s shadow-adjusted target is non-null, then set event’s eventPhase attribute to AT_TARGET.

      2. Otherwise:

        1. If event’s bubbles attribute is false, then continue.

        2. Set event’s eventPhase attribute to BUBBLING_PHASE.

      3. Invoke with struct, event, "bubbling", and legacyOutputDidListenersThrowFlag if given.

  7. Set event’s eventPhase attribute to NONE.

  8. Set event’s currentTarget attribute to null.

  9. Set event’s path to the empty list.

  10. Unset event’s dispatch flag, stop propagation flag, and stop immediate propagation flag.

  11. If clearTargets is true:

    1. Set event’s target to null.

    2. Set event’s relatedTarget to null.

    3. Set event’s touch target list to the empty list.

  12. If activationTarget is non-null:

    1. If event’s canceled flag is unset, then run activationTarget’s activation behavior with event.

    2. Otherwise, if activationTarget has legacy-canceled-activation behavior, then run activationTarget’s legacy-canceled-activation behavior.

  13. Return false if event’s canceled flag is set; otherwise true.

To append to an event path, given an event, invocationTarget, shadowAdjustedTarget, relatedTarget, touchTargets, and a slot-in-closed-tree, run these steps:

  1. Let invocationTargetInShadowTree be false.

  2. If invocationTarget is a node and its root is a shadow root, then set invocationTargetInShadowTree to true.

  3. Let root-of-closed-tree be false.

  4. If invocationTarget is a shadow root whose mode is "closed", then set root-of-closed-tree to true.

  5. Append a new struct to event’s path whose invocation target is invocationTarget, invocation-target-in-shadow-tree is invocationTargetInShadowTree, shadow-adjusted target is shadowAdjustedTarget, relatedTarget is relatedTarget, touch target list is touchTargets, root-of-closed-tree is root-of-closed-tree, and slot-in-closed-tree is slot-in-closed-tree.

To invoke, given a struct, event, phase, and an optional legacyOutputDidListenersThrowFlag, run these steps:

  1. Set event’s target to the shadow-adjusted target of the last struct in event’s path, that is either struct or preceding struct, whose shadow-adjusted target is non-null.

  2. Set event’s relatedTarget to struct’s relatedTarget.

  3. Set event’s touch target list to struct’s touch target list.

  4. If event’s stop propagation flag is set, then return.

  5. Initialize event’s currentTarget attribute to struct’s invocation target.

  6. Let listeners be a clone of event’s currentTarget attribute value’s event listener list.

    This avoids event listeners added after this point from being run. Note that removal still has an effect due to the removed field.

  7. Let invocationTargetInShadowTree be struct’s invocation-target-in-shadow-tree.

  8. Let found be the result of running inner invoke with event, listeners, phase, invocationTargetInShadowTree, and legacyOutputDidListenersThrowFlag if given.

  9. If found is false and event’s isTrusted attribute is true:

    1. Let originalEventType be event’s type attribute value.

    2. If event’s type attribute value is a match for any of the strings in the first column in the following table, set event’s type attribute value to the string in the second column on the same row as the matching string, and return otherwise.

      Event type Legacy event type
      "animationend" "webkitAnimationEnd"
      "animationiteration" "webkitAnimationIteration"
      "animationstart" "webkitAnimationStart"
      "transitionend" "webkitTransitionEnd"
    3. Inner invoke with event, listeners, phase, invocationTargetInShadowTree, and legacyOutputDidListenersThrowFlag if given.

    4. Set event’s type attribute value to originalEventType.

To inner invoke, given an event, listeners, phase, invocationTargetInShadowTree, and an optional legacyOutputDidListenersThrowFlag, run these steps:

  1. Let found be false.

  2. For each listener of listeners, whose removed is false:

    1. If event’s type attribute value is not listener’s type, then continue.

    2. Set found to true.

    3. If phase is "capturing" and listener’s capture is false, then continue.

    4. If phase is "bubbling" and listener’s capture is true, then continue.

    5. If listener’s once is true, then remove an event listener given event’s currentTarget attribute value and listener.

    6. Let global be listener callback’s associated realm’s global object.

    7. Let currentEvent be undefined.

    8. If global is a Window object:

      1. Set currentEvent to global’s current event.

      2. If invocationTargetInShadowTree is false, then set global’s current event to event.

    9. If listener’s passive is true, then set event’s in passive listener flag.

    10. If global is a Window object, then record timing info for event listener given event and listener.

    11. Call a user object’s operation with listener’s callback, "handleEvent", « event », and event’s currentTarget attribute value. If this throws an exception exception:

      1. Report exception for listener’s callback’s corresponding JavaScript object’s associated realm’s global object.

      2. Set legacyOutputDidListenersThrowFlag if given.

        The legacyOutputDidListenersThrowFlag is only used by Indexed Database API. [INDEXEDDB]

    12. Unset event’s in passive listener flag.

    13. If global is a Window object, then set global’s current event to currentEvent.

    14. If event’s stop immediate propagation flag is set, then break.

  3. Return found.

2.10. Firing events

To fire an event named e at target, optionally using an eventConstructor, with a description of how IDL attributes are to be initialized, and a legacy target override flag, run these steps:

  1. If eventConstructor is not given, then let eventConstructor be Event.

  2. Let event be the result of creating an event given eventConstructor, in the relevant realm of target.

  3. Initialize event’s type attribute to e.

  4. Initialize any other IDL attributes of event as described in the invocation of this algorithm.

    This also allows for the isTrusted attribute to be set to false.

  5. Return the result of dispatching event at target, with legacy target override flag set if set.

Fire in the context of DOM is short for creating, initializing, and dispatching an event. Fire an event makes that process easier to write down.

If the event needs its bubbles or cancelable attribute initialized, one could write "fire an event named submit at target with its cancelable attribute initialized to true".

Or, when a custom constructor is needed, "fire an event named click at target using MouseEvent with its detail attribute initialized to 1".

Occasionally the return value is important:

  1. Let doAction be the result of firing an event named like at target.

  2. If doAction is true, then …

2.11. Action versus occurrence

An event signifies an occurrence, not an action. Phrased differently, it represents a notification from an algorithm and can be used to influence the future course of that algorithm (e.g., through invoking preventDefault()). Events must not be used as actions or initiators that cause some algorithm to start running. That is not what they are for.

This is called out here specifically because previous iterations of the DOM had a concept of "default actions" associated with events that gave folks all the wrong ideas. Events do not represent or cause actions, they can only be used to influence an ongoing one.

3. Aborting ongoing activities

Though promises do not have a built-in aborting mechanism, many APIs using them require abort semantics. AbortController is meant to support these requirements by providing an abort() method that toggles the state of a corresponding AbortSignal object. The API which wishes to support aborting can accept an AbortSignal object, and use its state to determine how to proceed.

APIs that rely upon AbortController are encouraged to respond to abort() by rejecting any unsettled promise with the AbortSignal’s abort reason.

A hypothetical doAmazingness({ ... }) method could accept an AbortSignal object to support aborting as follows:

const controller = new AbortController();
const signal = controller.signal;

startSpinner();

doAmazingness({ ..., signal })
  .then(result => ...)
  .catch(err => {
    if (err.name == 'AbortError') return;
    showUserErrorMessage();
  })
  .then(() => stopSpinner());

// …

controller.abort();

doAmazingness could be implemented as follows:

function doAmazingness({signal}) {
  return new Promise((resolve, reject) => {
    signal.throwIfAborted();

    // Begin doing amazingness, and call resolve(result) when done.
    // But also, watch for signals:
    signal.addEventListener('abort', () => {
      // Stop doing amazingness, and:
      reject(signal.reason);
    });
  });
}

APIs that do not return promises can either react in an equivalent manner or opt to not surface the AbortSignal’s abort reason at all. addEventListener() is an example of an API where the latter made sense.

APIs that require more granular control could extend both AbortController and AbortSignal objects according to their needs.

3.1. Interface AbortController

[Exposed=*]
interface AbortController {
  constructor();

  [SameObject] readonly attribute AbortSignal signal;

  undefined abort(optional any reason);
};
controller = new AbortController()
Returns a new controller whose signal is set to a newly created AbortSignal object.
controller . signal
Returns the AbortSignal object associated with this object.
controller . abort(reason)
Invoking this method will store reason in this object’s AbortSignal’s abort reason, and signal to any observers that the associated activity is to be aborted. If reason is undefined, then an "AbortError" DOMException will be stored.

An AbortController object has an associated signal (an AbortSignal object).

The new AbortController() constructor steps are:

  1. Let signal be a new AbortSignal object.

  2. Set this’s signal to signal.

The signal getter steps are to return this’s signal.

The abort(reason) method steps are to signal abort on this with reason if it is given.

To signal abort on an AbortController controller with an optional reason, signal abort on controller’s signal with reason if it is given.

3.2. Interface AbortSignal

[Exposed=*]
interface AbortSignal : EventTarget {
  [NewObject] static AbortSignal abort(optional any reason);
  [Exposed=(Window,Worker), NewObject] static AbortSignal timeout([EnforceRange] unsigned long long milliseconds);
  [NewObject] static AbortSignal _any(sequence<AbortSignal> signals);

  readonly attribute boolean aborted;
  readonly attribute any reason;
  undefined throwIfAborted();

  attribute EventHandler onabort;
};
AbortSignal . abort(reason)
Returns an AbortSignal instance whose abort reason is set to reason if not undefined; otherwise to an "AbortError" DOMException.
AbortSignal . any(signals)
Returns an AbortSignal instance which will be aborted once any of signals is aborted. Its abort reason will be set to whichever one of signals caused it to be aborted.
AbortSignal . timeout(milliseconds)
Returns an AbortSignal instance which will be aborted in milliseconds milliseconds. Its abort reason will be set to a "TimeoutError" DOMException.
signal . aborted
Returns true if signal’s AbortController has signaled to abort; otherwise false.
signal . reason
Returns signal’s abort reason.
signal . throwIfAborted()
Throws signal’s abort reason, if signal’s AbortController has signaled to abort; otherwise, does nothing.

An AbortSignal object has an associated abort reason (a JavaScript value), which is initially undefined.

An AbortSignal object has associated abort algorithms, (a set of algorithms which are to be executed when it is aborted), which is initially empty.

The abort algorithms enable APIs with complex requirements to react in a reasonable way to abort(). For example, a given API’s abort reason might need to be propagated to a cross-thread environment, such as a service worker.

An AbortSignal object has a dependent (a boolean), which is initially false.

An AbortSignal object has associated source signals (a weak set of AbortSignal objects that the object is dependent on for its aborted state), which is initially empty.

An AbortSignal object has associated dependent signals (a weak set of AbortSignal objects that are dependent on the object for their aborted state), which is initially empty.


The static abort(reason) method steps are:

  1. Let signal be a new AbortSignal object.

  2. Set signal’s abort reason to reason if it is given; otherwise to a new "AbortError" DOMException.

  3. Return signal.

The static timeout(milliseconds) method steps are:

  1. Let signal be a new AbortSignal object.

  2. Let global be signal’s relevant global object.

  3. Run steps after a timeout given global, "AbortSignal-timeout", milliseconds, and the following step:

    1. Queue a global task on the timer task source given global to signal abort given signal and a new "TimeoutError" DOMException.

    For the duration of this timeout, if signal has any event listeners registered for its abort event, there must be a strong reference from global to signal.

  4. Return signal.

The static any(signals) method steps are to return the result of creating a dependent abort signal from signals using AbortSignal and the current realm.

The aborted getter steps are to return true if this is aborted; otherwise false.

The reason getter steps are to return this’s abort reason.

The throwIfAborted() method steps are to throw this’s abort reason, if this is aborted.

This method is primarily useful for when functions accepting AbortSignals want to throw (or return a rejected promise) at specific checkpoints, instead of passing along the AbortSignal to other methods. For example, the following function allows aborting in between each attempt to poll for a condition. This gives opportunities to abort the polling process, even though the actual asynchronous operation (i.e., await func()) does not accept an AbortSignal.

async function waitForCondition(func, targetValue, { signal } = {}) {
  while (true) {
    signal?.throwIfAborted();

    const result = await func();
    if (result === targetValue) {
      return;
    }
  }
}

The onabort attribute is an event handler IDL attribute for the onabort event handler, whose event handler event type is abort.

Changes to an AbortSignal object represent the wishes of the corresponding AbortController object, but an API observing the AbortSignal object can choose to ignore them. For instance, if the operation has already completed.


An AbortSignal object is aborted when its abort reason is not undefined.

To add an algorithm algorithm to an