Goals
This specification standardizes the DOM. It does so as follows:
-
By consolidating DOM Level 3 Core [DOM-Level-3-Core], Element Traversal [ELEMENTTRAVERSAL], Selectors API Level 2 [SELECTORS-API2], the "DOM Event Architecture" and "Basic Event Interfaces" chapters of DOM Level 3 Events [uievents-20031107] (specific types of events do not belong in the DOM Standard), and DOM Level 2 Traversal and Range [DOM-Level-2-Traversal-Range], and:
- Aligning them with the JavaScript ecosystem where possible.
- Aligning them with existing implementations.
- Simplifying them as much as possible.
-
By moving features from the HTML Standard [HTML] that make more sense to be specified as part of the DOM Standard.
-
By defining a replacement for the "Mutation Events" and "Mutation Name Event Types" chapters of DOM Level 3 Events [uievents-20031107] as the old model was problematic.
The old model is expected to be removed from implementations in due course.
-
By defining new features that simplify common DOM operations.
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]
The term context object means the object on which the algorithm, attribute getter, attribute setter, or method being discussed was called. When the context object is unambiguous, the term can be omitted.
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:
-
Let inputTokens be the result of splitting input on ASCII whitespace.
-
Let tokens be a new ordered set.
- 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:
-
Let s be the result of parse a selector selectors. [SELECTORS4]
-
If s is failure, then throw a "
SyntaxError
"DOMException
. -
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. Namespaces
To validate a qualifiedName, throw an
"InvalidCharacterError
" DOMException
if qualifiedName does not match
the Name
or QName
production.
To validate and extract a namespace and qualifiedName, run these steps:
- If namespace is the empty string, set it to null.
- Validate qualifiedName.
- Let prefix be null.
- Let localName be qualifiedName.
- If qualifiedName contains a "
:
" (U+003E), then split the string on it and set prefix to the part before and localName to the part after. - If prefix is non-null and namespace is null, then throw a
"
NamespaceError
"DOMException
. - If prefix is "
xml
" and namespace is not the XML namespace, then throw a "NamespaceError
"DOMException
. - If either qualifiedName or prefix is
"
xmlns
" and namespace is not the XMLNS namespace, then throw a "NamespaceError
"DOMException
. - If namespace is the XMLNS namespace and neither qualifiedName nor prefix is "
xmlns
", then throw a "NamespaceError
"DOMException
. - Return namespace, prefix, and localName.
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.
Events are objects too and implement the Event
interface (or a derived interface). In the example above ev is the event. It is
passed as argument to 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).
Now while typically events are dispatched by the user agent as the result of user interaction or the completion of some task, applications can dispatch events themselves, 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. First all object’s ancestor event listeners whose capture variable is set to true are invoked, in tree order. Second, object’s own event listeners are invoked. And
finally, and only if event’s bubbles
attribute value is true,
object’s ancestor event listeners are invoked again,
but now in reverse tree order.
Lets 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
[Constructor
(DOMStringtype
, optional EventIniteventInitDict
), Exposed=(Window,Worker,AudioWorklet)] interfaceEvent
{ readonly attribute DOMString type; readonly attribute EventTarget? target; 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; void stopPropagation(); attribute boolean cancelBubble; // historical alias of .stopPropagation void stopImmediatePropagation(); readonly attribute boolean bubbles; readonly attribute boolean cancelable; void preventDefault(); readonly attribute boolean defaultPrevented; readonly attribute boolean composed; [Unforgeable] readonly attribute boolean isTrusted; readonly attribute DOMHighResTimeStamp timeStamp; void initEvent(DOMStringtype
, optional booleanbubbles
= false, optional booleancancelable
= false); // historical }; dictionaryEventInit
{ booleanbubbles
= false; booleancancelable
= false; booleancomposed
= 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.
An event has an associated relatedTarget (null or an EventTarget
object). Unless stated otherwise it is null.
Other specifications use relatedTarget to define a relatedTarget
attribute. [UIEVENTS]
An event has an associated path. A path is a list of structs. Each struct consists of an item (an EventTarget
object), target (null
or an EventTarget
object), a relatedTarget (null or an EventTarget
object), root-of-closed-tree (a boolean), and a slot-in-closed-tree (a boolean). A path is initially the
empty list.
Specifications may define retargeting steps for all or some events. The algorithm is passed event, as indicated in the dispatch algorithm below.
event = new Event(type [, eventInitDict])
- Returns a new event whose
type
attribute value is set to type. The optional eventInitDict argument allows for setting thebubbles
andcancelable
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.
event .
currentTarget
- Returns the object whose event listener’s callback is currently being invoked.
event .
composedPath()
- Returns the item 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’scurrentTarget
. event .
eventPhase
- Returns the event’s phase, which is one of
NONE
,CAPTURING_PHASE
,AT_TARGET
, andBUBBLING_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
attribute value’s ancestors in reverse tree order, and false otherwise. 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 withpassive
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, and false otherwise. 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 itstarget
attribute value, and false otherwise. 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 time origin.
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
and currentTarget
attributes must return the values they were initialized to. When an event is created the attributes must be
initialized to null.
The composedPath()
method, when invoked, must run these
steps:
-
Let reversedComposedPath be an empty list.
-
Let hiddenSubtreeLevel be 0.
-
Let hasSeenCurrentTarget be false.
-
Let currentTarget be context object’s
currentTarget
attribute value. -
Let reversedPath be context object’s path, in reverse order.
-
For each struct in reversedPath:
-
If struct’s item is currentTarget, then set hasSeenCurrentTarget to true.
-
Otherwise, if hasSeenCurrentTarget is true and struct’s root-of-closed-tree is true, then increase hiddenSubtreeLevel by
-
If hiddenSubtreeLevel is 0, then append struct’s item to reversedComposedPath.
-
If struct’s slot-in-closed-tree is true and hiddenSubtreeLevel is greater than 0, then decrease hiddenSubtreeLevel by
-
-
Return reversedComposedPath, in reverse order.
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
attribute value. AT_TARGET
(numeric value 2)- When an event is dispatched it will be in this
phase on its
target
attribute value. 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
attribute value.
NONE
.
Each event has the following associated flags that are all initially unset:
- stop propagation flag
- stop immediate propagation flag
- canceled flag
- in passive listener flag
- composed flag
- initialized flag
- dispatch flag
The stopPropagation()
method, when invoked, must set the context object’s stop propagation flag.
The cancelBubble
attribute’s getter must return true
if context object’s stop propagation flag is set, and false otherwise.
The cancelBubble
attribute’s setter must set context object’s stop propagation flag if the given value is true, and do nothing otherwise.
The stopImmediatePropagation()
method, when invoked,
must set context object’s stop propagation flag and context object’s stop immediate propagation flag.
The bubbles
and cancelable
attributes
must return the values they were initialized to.
The preventDefault()
method, when invoked, must set the canceled flag if the cancelable
attribute value is true and the in passive listener flag is unset.
This means 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
attribute’s getter must return
true if context object’s canceled flag is set, and false otherwise.
The composed
attribute’s getter must return true if context object’s composed flag is set, and false otherwise.
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:
- Set the initialized flag.
- Unset the stop propagation flag, stop immediate propagation flag, and canceled flag.
- Set the
isTrusted
attribute to false. - Set the
target
attribute to null. - Set the
type
attribute to type. - Set the
bubbles
attribute to bubbles. - Set the
cancelable
attribute to cancelable.
The initEvent(type, bubbles, cancelable)
method, when invoked, must run these steps:
-
If context object’s dispatch flag is set, then return.
-
Initialize context object with type, bubbles, and cancelable.
As events have constructors initEvent()
is redundant and
incapable of setting composed
. It has to be supported for legacy content.
2.3. Interface CustomEvent
[Constructor
(DOMStringtype
, optional CustomEventIniteventInitDict
), Exposed=(Window,Worker)] interfaceCustomEvent
: Event { readonly attribute any detail; void initCustomEvent(DOMStringtype
, optional booleanbubbles
= false, optional booleancancelable
= false, optional anydetail
= null); }; dictionaryCustomEventInit
: EventInit { anydetail
= 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 optional eventInitDict argument now allows for setting thedetail
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 must, when invoked, run these steps:
- If context object’s dispatch flag is set, then return.
- Initialize the context object with type, bubbles, and cancelable.
- Set context object’s
detail
attribute to detail.
2.4. Constructing events
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:
-
Let event be the result of running the inner event creation steps with this interface, null, now, and eventInitDict.
-
Initialize event’s
type
attribute to type. -
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:
-
If realm is not given, then set it to null.
-
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.
-
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 ofNSEvent
objects. -
Initialize event’s
isTrusted
attribute to true. -
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 interface, realm, time, and dictionary, are as follows:
-
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 heycam/webidl#135.
-
Set event’s initialized flag.
-
Initialize event’s
timeStamp
attribute to aDOMHighResTimeStamp
representing the high resolution time from the time origin to time.User agents should set a minimum resolution of event’s
timeStamp
attribute to 5 microseconds following the existing clock resolution recommendation. [HR-TIME] -
For each member → value in dictionary, if event has an attribute whose identifier is member, then initialize that attribute to value.
-
Return event.
2.5. 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.6. Interface EventTarget
[Constructor, Exposed=(Window,Worker,AudioWorklet)] interfaceEventTarget
{ void addEventListener(DOMStringtype
, EventListener?callback
, optional (AddEventListenerOptions or boolean)options
); void removeEventListener(DOMStringtype
, EventListener?callback
, optional (EventListenerOptions or boolean)options
); boolean dispatchEvent(Eventevent
); }; callback interfaceEventListener
{ voidhandleEvent
(Eventevent
); }; dictionaryEventListenerOptions
{ booleancapture
= false; }; dictionaryAddEventListenerOptions
: EventListenerOptions { booleanpassive
= false; booleanonce
= false; };
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:
- type (a string)
- callback (null or an
EventListener
object) - capture (a boolean, initially false)
- passive (a boolean, initially false)
- once (a boolean, initially false)
- removed (a boolean for bookkeeping purposes, initially false)
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’seventPhase
attribute value isBUBBLING_PHASE
. When false (or not present), callback will not be invoked when event’seventPhase
attribute value isCAPTURING_PHASE
. Either way, callback will be invoked if event’seventPhase
attribute value isAT_TARGET
.When set to true, options’s
passive
indicates that the callback will not cancel the event by invokingpreventDefault()
. This is used to enable performance optimizations described in §2.7 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.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 itspreventDefault()
method was not invoked, and false otherwise.
To flatten options, run these steps:
-
If options is a boolean, then return options.
-
Return options’s
.capture
To flatten more options, run these steps:
-
Let capture be the result of flattening options.
-
Let once and passive be false.
-
If options is a dictionary, then set passive to options’s
and once to options’spassive
.once
-
Return capture, passive, and once.
The EventTarget()
constructor, when invoked,
must return a new EventTarget
.
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 EventTarget
s do not
participate in a tree structure.
To add an event listener given an EventTarget
object eventTarget and an event listener listener, run these steps:
-
If eventTarget’s relevant global object is a
ServiceWorkerGlobalScope
object and its associated service worker’s script resource’s has ever been evaluated flag is set, then throw aTypeError
. [SERVICE-WORKERS]To optimize storing the event types allowed for the service worker and to avoid non-deterministic changes to the event listeners, invocation of the method is allowed only during the very first evaluation of the service worker script.
-
If listener’s callback is null, then return.
-
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.
The add an event listener concept exists to ensure event handlers use the same code path. [HTML]
The addEventListener(type, callback, options)
method, when invoked, must run these steps:
-
Let capture, passive, and once be the result of flattening more options.
-
Add an event listener with the context object and an event listener whose type is type, callback is callback, capture is capture, passive is passive, and once is once.
The removeEventListener(type, callback, options)
method, when invoked, must run these steps:
-
If the context object’s relevant global object is a
ServiceWorkerGlobalScope
object and its associated service worker’s script resource’s has ever been evaluated flag is set, then throw aTypeError
. [SERVICE-WORKERS] -
Let capture be the result of flattening options.
-
If the context object’s event listener list contains an event listener whose type is type, callback is callback, and capture is capture, then set that event listener’s removed to true and remove it from the context object’s event listener list.
The dispatchEvent(event)
method, when
invoked, must run these steps:
-
If event’s dispatch flag is set, or if its initialized flag is not set, then throw an "
InvalidStateError
"DOMException
. -
Initialize event’s
isTrusted
attribute to false. -
Return the result of dispatching event to context object.
2.7. 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 public-script-coord@w3.org for discussion).
2.8. Dispatching events
To dispatch an event to a target, with an optional legacy target override flag and an optional legacyOutputDidListenersThrowFlag, run these steps:
-
Set event’s dispatch flag.
-
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. - Let relatedTarget be the result of retargeting event’s relatedTarget against target if event’s relatedTarget is non-null, and null otherwise.
-
If target is relatedTarget and target is not event’s relatedTarget, then return true.
-
Append to an event path with event, target, targetOverride, relatedTarget, and false.
-
Let isActivationEvent be true, if event is a
MouseEvent
object and event’stype
attribute is "click
", and false otherwise. -
Let activationTarget be target, if isActivationEvent is true and target has activation behavior, and null otherwise.
-
Let slotable be target, if target is assigned, and null otherwise.
-
Let slot-in-closed-tree be false.
-
Let parent be the result of invoking target’s get the parent with event.
-
While parent is non-null:
-
If slotable is non-null:
-
Assert: parent is a slot.
-
Set slotable to null.
-
If parent’s root is a shadow root whose mode is "
closed
", then set slot-in-closed-tree to true.
-
-
If parent is assigned, then set slotable to parent.
-
Let relatedTarget be the result of retargeting event’s relatedTarget against parent if event’s relatedTarget is non-null, and null otherwise.
-
If target’s root is a shadow-including inclusive ancestor of parent, then:
-
If isActivationEvent is true, event’s
bubbles
attribute is true, activationTarget is null, and parent has activation behavior, then set activationTarget to parent. -
Append to an event path with event, parent, null, relatedTarget, and slot-in-closed-tree.
-
-
Otherwise, if parent and relatedTarget are identical, then set parent to null.
-
Otherwise, set target to parent and then:
-
If isActivationEvent is true, activationTarget is null, and target has activation behavior, then set activationTarget to target.
-
Append to an event path with event, parent, target, relatedTarget, and slot-in-closed-tree.
-
-
If parent is non-null, then set parent to the result of invoking parent’s get the parent with event.
-
Set slot-in-closed-tree to false.
-
-
Set event’s
eventPhase
attribute toCAPTURING_PHASE
. -
If activationTarget is non-null and activationTarget has legacy-pre-activation behavior, then run activationTarget’s legacy-pre-activation behavior.
-
For each tuple in event’s path, in reverse order:
-
Set event’s
target
attribute to the target of the last tuple in event’s path, that is either tuple or preceding tuple, whose target is non-null. -
Set event’s relatedTarget to tuple’s relatedTarget.
-
Run the retargeting steps with event.
-
If tuple’s target is null, then invoke tuple’s item with event and legacyOutputDidListenersThrowFlag if given.
-
-
For each tuple in event’s path, in order:
-
Set event’s
target
attribute to the target of the last tuple in event’s path, that is either tuple or preceding tuple, whose target is non-null. -
Set event’s relatedTarget to tuple’s relatedTarget.
-
Run the retargeting steps with event.
-
If tuple’s target is non-null, then set event’s
eventPhase
attribute toAT_TARGET
. -
Otherwise, set event’s
eventPhase
attribute toBUBBLING_PHASE
. -
If either event’s
eventPhase
attribute isBUBBLING_PHASE
and event’sbubbles
attribute is true or event’seventPhase
attribute isAT_TARGET
, then invoke tuple’s item with event and legacyOutputDidListenersThrowFlag if given.
-
-
Unset event’s dispatch flag, stop propagation flag, and stop immediate propagation flag.
-
Set event’s
eventPhase
attribute toNONE
. -
If
target
's root is a shadow root, then set event’starget
attribute and event’s relatedTarget to null. -
Set event’s
currentTarget
attribute to null. -
Set event’s path to the empty list.
-
If activationTarget is non-null, then:
-
If event’s canceled flag is unset, then run activationTarget’s activation behavior with event.
-
Otherwise, if activationTarget has legacy-canceled-activation behavior, then run activationTarget’s legacy-canceled-activation behavior.
-
-
Return false if event’s canceled flag is set, and true otherwise.
To append to an event path, given an event, target, targetOverride, relatedTarget, and a slot-in-closed-tree, run these steps:
-
Let root-of-closed-tree be false.
-
If target is a shadow root whose mode is "
closed
", then set root-of-closed-tree to true. -
Append a new struct to event’s path whose item is target, target is targetOverride, relatedTarget is relatedTarget, root-of-closed-tree is root-of-closed-tree, and slot-in-closed-tree is slot-in-closed-tree.
To invoke an object with event and an optional legacyOutputDidListenersThrowFlag, run these steps:
-
If event’s stop propagation flag is set, then return.
-
Let listeners be a new list.
-
For each listener of object’s event listener list, append listener to listeners.
This avoids event listeners added after this point from being run. Note that removal still has an effect due to the removed field.
-
Initialize event’s
currentTarget
attribute to object. -
Let found be the result of running inner invoke object with event, listeners, and legacyOutputDidListenersThrowFlag if given.
-
If found is false and event’s
isTrusted
attribute is true, then:-
Let originalEventType be event’s
type
attribute value. -
If event’s
type
attribute value is a match for any of the strings in the first column in the following table, set event’stype
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
" -
Inner invoke object with event, listeners, and legacyOutputDidListenersThrowFlag if given.
-
Set event’s
type
attribute value to originalEventType.
-
To inner invoke an object with event, listeners, and an optional legacyOutputDidListenersThrowFlag, run these steps:
-
Let found be false.
-
For each listener in listeners, whose removed is false:
-
If event’s
type
attribute value is not listener’s type, then continue. -
Set found to true.
-
If event’s
eventPhase
attribute value isCAPTURING_PHASE
and listener’s capture is false, then continue. -
If event’s
eventPhase
attribute value isBUBBLING_PHASE
and listener’s capture is true, then continue. -
If listener’s once is true, then remove listener from object’s event listener list.
-
If listener’s passive is true, then set event’s in passive listener flag.
-
Call a user object’s operation with listener’s callback, "
handleEvent
", « event », and event’scurrentTarget
attribute value. If this throws an exception, then:-
Set legacyOutputDidListenersThrowFlag if given.
The legacyOutputDidListenersThrowFlag is only used by Indexed Database API. [INDEXEDDB]
-
Unset event’s in passive listener flag.
-
If event’s stop immediate propagation flag is set, then return found.
-
-
Return found.
2.9. 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:
-
If eventConstructor is not given, then let eventConstructor be
Event
. -
Let event be the result of creating an event given eventConstructor, in the relevant Realm of target.
-
Initialize event’s
type
attribute to e. -
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. -
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:
-
Let doAction be the result of firing an event named
like
at target. -
If doAction is true, then …
2.10. 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 a new "AbortError
" DOMException
.
A hypothetical doAmazingness({ ... })
method could accept an AbortSignal
object
in order 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}) {
if (signal.aborted) {
return Promise.reject(new DOMException('Aborted', 'AbortError'));
}
return new Promise((resolve, reject) => {
// Begin doing amazingness, and call resolve(result) when done.
// But also, watch for signals:
signal.addEventListener('abort', () => {
// Stop doing amazingness, and:
reject(new DOMException('Aborted', 'AbortError'));
});
});
}
APIs that require more granular control could extend both AbortController
and AbortSignal
objects according to their needs.
3.1. Interface AbortController
[Constructor,
Exposed=(Window,Worker)]
interface AbortController
{
[SameObject] readonly attribute AbortSignal signal;
void abort();
};
controller = new AbortController()
- Returns a new controller whose
signal
is set to a newly createdAbortSignal
object. controller . signal
- Returns the
AbortSignal
object associated with this object. controller . abort()
- Invoking this method will set this object’s
AbortSignal
's aborted flag and signal to any observers that the associated activity is to be aborted.
An AbortController
object has an associated signal (an AbortSignal
object).
The AbortController()
constructor, when
invoked, must run these steps:
-
Let signal be a new
AbortSignal
object. -
Let controller be a new
AbortController
object whose signal is signal. -
Return controller.
The signal
attribute’s getter must return context object’s signal.
The abort()
method, when invoked, must signal abort on context object’s signal.
3.2. Interface AbortSignal
[Exposed=(Window,Worker)] interfaceAbortSignal
: EventTarget { readonly attribute boolean aborted; attribute EventHandleronabort
; };
signal . aborted
- Returns true if this
AbortSignal
'sAbortController
has signaled to abort, and false otherwise.
An AbortSignal
object has an associated aborted flag. It is
unset unless specified otherwise.
An AbortSignal
object has associated abort algorithms, which is a set of algorithms which are to be executed when its aborted flag is
set. Unless specified otherwise, its value is the empty set.
To add an algorithm algorithm to an AbortSignal
object signal, run these steps:
-
If signal’s aborted flag is set, then return.
-
Append algorithm to signal’s abort algorithms.
To remove an algorithm algorithm from an AbortSignal
signal, remove algorithm from signal’s abort algorithms.
The abort algorithms enable APIs with complex
requirements to react in a reasonable way to abort()
. For example, a given API’s aborted flag might need to be propagated to a cross-thread environment, such as a
service worker.
The aborted
attribute’s getter must return true if context object’s aborted flag is set, and false otherwise.
Changes to an AbortSignal
object represent the wishes of the corresponding AbortController
object, but an API observing the AbortSignal
object can chose to ignore
them. For instance, if the operation has already completed.
To signal abort, given a AbortSignal
object signal, run these steps:
-
If signal’s aborted flag is set, then return.
-
Set signal’s aborted flag.
-
For each algorithm in signal’s abort algorithms: run algorithm.
-
Empty signal’s abort algorithms.
-
Fire an event named
abort
at signal.
A followingSignal (an AbortSignal
) is made to follow a parentSignal (an AbortSignal
) by running
these steps:
-
If followingSignal’s aborted flag is set, then return.
-
If parentSignal’s aborted flag is set, then signal abort on followingSignal.
-
Otherwise, add the following abort steps to parentSignal:
-
Signal abort on followingSignal.
-
3.3. Using AbortController
and AbortSignal
objects in
APIs
Any web platform API using promises to represent operations that can be aborted must adhere to the following:
- Accept
AbortSignal
objects through asignal
dictionary member. - Convey that the operation got aborted by rejecting the promise with an
"
AbortError
"DOMException
. - Reject immediately if the
AbortSignal
's aborted flag is already set, otherwise: - Use the abort algorithms mechanism to observe changes to the
AbortSignal
object and do so in a manner that does not lead to clashes with other observers.
The steps for a promise-returning method doAmazingness(options)
could be as
follows:
-
Let p be a new promise.
-
If options’
signal
member is present, then:-
If options’
signal
’s aborted flag is set, then reject p with an "AbortError
"DOMException
and return p. -
Add the following abort steps to options’
signal
:-
Stop doing amazing things.
-
Reject p with an "
AbortError
"DOMException
.
-
-
-
Run these steps in parallel:
-
Let amazingResult be the result of doing some amazing things.
-
Resolve p with amazingResult.
-
-
Return p.
APIs not using promises should still adhere to the above as much as possible.
4. Nodes
4.1. Introduction to "The DOM"
In its original sense, "The DOM" is an API for accessing and manipulating documents (in particular, HTML and XML documents). In this specification, the term "document" is used for any markup-based resource, ranging from short static documents to long essays or reports with rich multimedia, as well as to fully-fledged interactive applications.
Each such document is represented as a node tree. Some of the nodes in a tree can have children, while others are always leaves.
To illustrate, consider this HTML document:
<!DOCTYPE html> <html class=e> <head><title>Aliens?</title></head> <body>Why yes.</body> </html>
It is represented as follows:
Note that, due to the magic that is HTML parsing, not all ASCII whitespace were turned into Text
nodes, but the general concept is
clear. Markup goes in, a tree of nodes comes out.
The most excellent Live DOM Viewer can be used to explore this matter in more detail.
4.2. Node tree
Document
, DocumentType
, DocumentFragment
, Element
, Text
, ProcessingInstruction
, and Comment
objects (simply called nodes) participate in a tree, simply named the node tree.
A node tree is constrained as follows, expressed as a relationship between the type of node and its allowed children:
Acknowledgments
There have been a lot of people that have helped make DOM more interoperable over the years and thereby furthered the goals of this standard. Likewise many people have helped making this standard what it is today.
With that, many thanks to Adam Klein, Adrian Bateman, Aleksey Shvayka, Alex Komoroske, Alex Russell, Anthony Ramine, Arkadiusz Michalski, Arnaud Le Hors, Arun Ranganathan, Björn Höhrmann, Boris Zbarsky, Brandon Payton, Brandon Slade, Brandon Wallace, Brian Kardell, Cameron McCormack, Chris Dumez, Chris Paris, Chris Rebert, Cyrille Tuzi, Daniel Glazman, Darin Fisher, David Bruant, David Flanagan, David Håsäther, David Hyatt, Deepak Sherveghar, Dethe Elza, Dimitri Glazkov, Domenic Denicola, Dominic Cooney, Dominique Hazaël-Massieux, Don Jordan, Doug Schepers, Edgar Chen, Elisée Maurer, Elliott Sprehn, Eric Bidelman, Erik Arvidsson, Gary Kacmarcik, Gavin Nicol, Geoffrey Sneddon, Giorgio Liscio, Glen Huang, Glenn Adams, Glenn Maynard, Hajime Morrita, Harald Alvestrand, Hayato Ito, Henri Sivonen, Hongchan Choi, Hunan Rostomyan, Ian Hickson, Igor Bukanov, Jacob Rossi, Jake Archibald, Jake Verbaten, James Graham, James Greene, James Robinson, Jeffrey Yasskin, Jens Lindström, Jesse McCarthy, Jinho Bang, João Eiras, Joe Kesselman, John Atkins, John Dai, Jonas Sicking, Jonathan Robie, Joris van der Wel, Joshua Bell, Jungkee Song, Justin Summerlin, 呂康豪 (Kang-Hao Lu), Kevin Sweeney, Kirill Topolyan, Koji Ishii, Lachlan Hunt, Lauren Wood, Magne Andersson, Majid Valipour, Malte Ubl, Manish Goregaokar, Manish Tripathi, Marcos Caceres, Mark Miller, Martijn van der Ven, Mats Palmgren, Mounir Lamouri, Michael™ Smith, Mike Champion, Mike Taylor, Mike West, Ojan Vafai, Oliver Nightingale, Olli Pettay, Ondřej Žára, Peter Sharpe, Philip Jägenstedt, Philippe Le Hégaret, Ra’Shaun Stovall (Snuggs), Rafael Weinstein, Richard Bradshaw, Rick Byers, Rick Waldron, Robbert Broersma, Robin Berjon, Roland Steiner, Rune F. Halvorsen, Russell Bicknell, Ruud Steltenpool, Ryosuke Niwa, Sam Dutton, Samuel Giles, Sebastian Mayr, Seo Sanghyeon, Sergey G. Grekhov, Shiki Okasaka, Shinya Kawanaka, Simon Pieters, Stef Busking, Steve Byrne, Stig Halvorsen, Tab Atkins, Takashi Sakamoto, Takayoshi Kochi, Theresa O’Connor, timeless, Timo Tijhof, Tobie Langel, Tom Pixley, Travis Leithead, triple-underscore, Veli Şenol, Vidur Apparao, Warren He, Xidorn Quan, Yehuda Katz, Yoav Weiss, Yoichi Osato, Yoshinori Sano, and Zack Weinberg for being awesome!
This standard is written by Anne van Kesteren (Mozilla, annevk@annevk.nl) with substantial contributions from Aryeh Gregor (ayg@aryeh.name) and Ms2ger (ms2ger@gmail.com).
Part of the revision history of the integration points related to custom elements can be found in the w3c/webcomponents repository, which is available under the W3C Permissive Document License.
Copyright © 2018 WHATWG (Apple, Google, Mozilla, Microsoft) and W3C® (MIT, ERCIM, Keio, Beihang). This work is licensed under a Creative Commons Attribution 4.0 International License. W3C liability and trademark rules apply.
W3C Recommendation Status
This Living Standard is also endorsed as a W3C (Candidate Recommendation|Proposed Recommendation|Recommendation) (choose one and update as it proceeds through the process) under the terms of the Memorandum of Understanding. For those purposes, it contains the following metadata:
- Canonical version / latest Living Standard:
- https://dom.spec.whatwg.org/
- This version:
- https://dom.spec.whatwg.org/review-drafts/2018-03-21
- W3C Version Mnenomic:
- DOM 2018-03
- Status of This Document
-
This section describes the status of this document at the time of its publication. Other documents may supersede this document. A list of current W3C publications and the latest revision of this technical report can be found in the W3C technical reports index at https://www.w3.org/TR/.
[if Recommendation] Please check the errata for any critical errors or issues reported since publication.
[if Candidate Recommendation] The following features are at-risk for the purpose of the W3C Candidate Recommendation:
- [list of features and their associated sections/characterization]
[if [Proposed] Recommendation] The following are non-normative for the purpose of the W3C [Proposed] Recommendation:
- [list of sections/characterization]
The W3C HTML Working Group co-produced this document under the W3C Patent Policy and the 1 February 2018 W3C Process Document. W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An individual who has actual knowledge of a patent which the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy.