This specification describes a method of combining multiple DOM trees into one hierarchy and how these trees interact with each other within a document, thus enabling better composition of the DOM.

Conformance

All diagrams, examples, notes, are non-normative, as well as sections explicitly marked as non-normative. Everything else in this specification is normative.

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in the normative parts of this document are to be interpreted as described in [[!RFC2119]]. For readability, these words do not appear in all uppercase letters in this specification.

To help with layering and to avoid circular dependencies between various parts of specification, this document consists of three consecutive narratives:

  1. setting up the stage for the specification,
  2. explaining of the conceptual model and algorithms behind it, and
  3. expressing this model with DOM interfaces and HTML elements.

In a sense, these parts can be viewed as math, which sets up the reasoning environment, physics, which is the theoretical reasoning about the concept, and mechanics, which is the practical application of this reasoning.

Any point, at which a conforming UA must make decisions about the state or reaction to the state of the conceptual model, is captured as algorithm. The algorithms are defined in terms of processing equivalence. The processing equivalence is a constraint imposed on the algorithm implementors, requiring the output of the both UA-implemented and the specified algorithm to be exactly the same for all inputs.

Composition

Shadow trees

Shadow DOM specification is being upstreamed to DOM Standard [[!WHATWG-DOM]]. Most of the concepts about shadow trees are now being defined in DOM Standard.

An element A is a shadow host if A is a host that is associated with a shadow root B. In this case, A hosts a shadow tree whose root is B.

A node A is called a shadow-including child of a node B, if A is a child of B, or A is a shadow root and B is the host of A.

A node A is called a shadow-including parent of a node B, if B is a shadow-including child of A.

A node A is called a shadow-including ancestor of a node B if B is a shadow-including descendant of A.

An shadow-including inclusive ancestor is a node or one of its shadow-including ancestors.

A node A is an unclosed node of a node B, if A's root is a shadow-including inclusive ancestor of B, or A's root is a shadow root whose associated mode is "open" and the root's host is an unclosed node of B.

Window object named properties [[!HTML]] must access the nodes in the document tree.

Composed trees

The specification no longer uses the concept of a composed tree of node trees in normative sections.

A composed tree of node trees is a tree of node trees.

Just like a node tree is defined as a set of relationships between nodes, a composed tree of node trees is similarly defined as a set of relationships between node trees:

A composed document is a composed tree of node trees whose root tree is a document tree.

Example composed tree of node trees

A composed tree of node trees.

In the figure, there are six node trees, named A, B, C, D, E and F. The shadow trees, B, C and D, are hosted by elements which participate in the document tree A. The shadow trees, E and F, are hosted by elements which participates in the shadow tree D. The following set of relationships holds in the figure:

As for a relationship between nodes, it's worth mentioning that there is no ancestor/descendant relationships between two nodes if they participate in different node trees. A shadow root is not a child node of the shadow host. The parent node of a shadow root doesn't exist. Because of this nature, most of existing APIs are scoped and don't affect other node trees, even though they are forming one composed tree of node trees. For example, document.getElementById(elementId) never returns an element in a shadow tree, even when the element has the given elementId.

The same thing also applies to CSS Selectors matching. For example, a descendant combinator never descends into a node in a child shadow tree because a shadow root is not a child node of the shadow host. Unless a special CSS Selector for Shadow DOM, which is mentioned later, is used, a CSS Selector never matches an element in a different node tree.

Because ShadowRoot inherits DocumentFragment, as specified later, you can use ShadowRoot.getElementByID(elementId) to get a node in the shadow tree.

Flat trees

A flat tree is a node tree which is constructed out of nodes that share the same shadow-including root. The exact algorithm of constructing a flat tree is specified later.

A flat tree

A document flat tree is a flat tree whose root node is a document

A node is in a document flat tree if it participates in a document flat tree.

Unless an element is in a document flat tree, the element must not create any CSS box.

In resolving CSS inheritance, an element must inherit from the parent node in the flat tree, if applicable.

User agents must use the document flat tree in the visual formatting model, instead of the document tree.

The editor's draft of CSS Scoping specification [[css-scoping-1]] defines the selectors which are related to Shadow DOM. Specifically, it defines the following selectors related to Shadow DOM:

  • ::shadow pseudo element
  • /deep/ combinator, which was replaced with a >>> combinator (or shadow piercing descendant combinator)
  • ::content pseudo-element
  • :host pseudo-class and :host() functional pseudo-class
  • :host-context() functional pseudo-class

Distributions

Slots

The slot element represents an instruction element, called slot.

User agents must have the following rule in their user agent style sheets:

        slot { display: contents; }
        

A node can be assigned to a slot, called an assigned slot. The exact algorithm of determining the assigned slot for a node is specified later.

A node is called slot assignable if it is either Text or Element.

A distribution is the mechanism that determines which nodes appear as child nodes of a slot in a flat tree. The exact algorithm of a distribution is specified later.

A distribution.

The figure should be updated so that the flat tree should includes a slot.

A slot name is the name of a slot.

A default slot is the first slot element, in tree order, in a node tree, whose slot name is the empty string or missing.

Slotting Algorithm

The slotting algorithm must be used to determine the assigned slot of each node and must be equivalent to processing the following steps:

Input
NODE, a node
Output
(nullable) SLOT, a slot to which NODE is assigned.
  1. If NODE is slot assignable and the parent node of NODE is a shadow host:
    1. Let TREE be the shadow tree that the parent node of NODE hosts
    2. Let NAME be the value of the slot attribute of NODE
    3. If NAME is the empty string or missing:
      1. Let SLOT be a default slot for TREE if it exists, Otherwise, null
    4. Otherwise:
      1. Let SLOT be the first slot element, in tree order, in TREE, whose slot name is NAME, and null if there is no such slot element otherwise.
  2. Otherwise:
    1. Let SLOT be null

Assigned Nodes Algorithm

The get assigned nodes algorithm must be used to determine the assigned nodes of a slot and must be equivalent to processing the following steps:

Input
SLOT, a slot
Output
ASSIGNED-NODES, an ordered list of nodes
  1. If SLOT participates in a shadow tree:
    1. Let HOST be a shadow host which hosts the shadow tree
    2. For each child node NODE of HOST:
      1. If NODE is assigned to SLOT:
        1. Append NODE to ASSIGNED-NODES

Distributed Nodes Algorithm

The get distributed nodes algorithm must be used to determine the distributed nodes of a slot and must be equivalent to processing the following steps:

Input
SLOT, a slot
Output
DISTRIBUTED-NODES, an ordered list of nodes.
  1. If the assigned nodes of SLOT is empty:
    1. Let ASSIGNED-OR-FALLBACK-CONTENT be the child nodes of SLOT
  2. Otherwise:
    1. Let ASSIGNED-OR-FALLBACK-CONTENT be the assigned nodes of SLOT
  3. For each node NODE of ASSIGNED-OR-FALLBACK-CONTENT:
    1. If NODE is a slot:
      1. Let SUB-LIST be the result of (recursively) running the get distributed nodes algorithm with NODE as input
      2. Append all nodes in SUB-LIST to DISTRIBUTED-NODES
    2. Otherwise:
      1. Append NODE to DISTRIBUTED-NODES if NODE is slot assignable

Flattening

Flattening Algorithm

The flat tree constructed from the nodes who share the same shadow-including root ROOT must be equivalent to the following tree:

The flat tree children calculation algorithm must be used to determine the child nodes of a node in the flat tree and must be equivalent to processing the following steps:

Input
NODE, a node which participates in a flat tree
Output
CHILDREN, the child nodes of NODE in the flat tree.
  1. If NODE is a slot:
    1. If the assigned nodes of SLOT is empty:
      1. Let CHILDREN be the slot assignable child nodes of SLOT.
    2. Otherwise:
      1. Let CHILDREN be the assigned nodes of SLOT.
  2. Otherwise, if NODE is a shadow host:
    1. Let CHILDREN be the slot assignable child nodes of shadow root which NODE hosts.
  3. Otherwise,
    1. Let CHILDREN be the slot assignable child nodes of NODE.

Flattening Example

This non-normative section should be updated so that a flat tree should includes slots.

Suppose that we have the following composed tree of node trees:

An example composed tree of node trees. A node whose color is red represents a slot. Unlike the previous figures, a box surrounding a node tree is omitted here.

This composed tree of node trees is composed of the following 3 node trees, one document tree and two shadow trees:

node tree Root node is: Hosted by: Composed of: (in tree order)
document tree 1 A - A, B, C, D, E, F, G, H, I
shadow tree 1 J C J, K, L, M, N, O, P, Q
shadow tree 2 R N R, S, T

Suppose that an assigned slot of each node, if it exists, is:

A result of slotting.

Then, the assigned nodes and the distributed nodes of each slot will be:

node tree Root node is: Hosted by: Composed of: (in tree order) Assigned slot of each node Assigned nodes of each slot Distributed nodes of each slot
document tree 1 A - A, B, C, D, E, F, G, H, I
  • D: => L
  • F: => L
  • H: => O
- -
shadow tree 1 J C J, K, L, M, N, O, P, Q
  • O: => T
  • P: => T
  • L: [D, F]
  • M: []
  • O: [H]
  • L: [D, F]
  • M: []
  • O: [H]
shadow tree 2 R N R, S, T -
  • T: [O, P]
  • T: [H, P]

The document flat tree will be:

Document flat tree.

Events

In each algorithm in this section, the Window must be considered as if it were the parent node of the Document so that the Window also receives an event.

This section assumes that an event target is a Node object. This section is not applied for an event whose event target is not a Node object, such as IndexedDB, XHR and so on. See Issue #61 for details. Eventually, DOM Standard should clarify this.

Event Paths

scoped flag

A trusted event's scoped flag must be initialized to true if the event is one of the following events: abort, error, select, change, load, loadedmetadata, reset, resize, scroll and selectstart.

get the parent

The get the parent algorithm associated with Node must be equivalent to processing the following steps:

Input
NODE, a context object
TARGET, an eventPath's last item
EVENT, an event
Output
PARENT, the parent
  1. If all of the following conditions are satisfied, let PARENT be null:
    1. NODE is a shadow root
    2. NODE is the root node of TARGET
    3. EVENT's scoped flag is true
  2. Otherwise, if all of the following conditions are satisfied, let PARENT be null:
    1. EVENT has a relatedTarget property whose value is non-null
    2. Either TARGET's root is a shadow root or EVENT's relatedTarget's root is a shadow root
    3. The relative target and the relative related target are the same, where:
  3. Otherwise, if NODE is assigned to a slot SLOT:
    1. Let PARENT be SLOT
  4. Otherwise:
    1. Let PARENT be the shadow-including parent of NODE

The definitions of retargeting algorithm is specified later.

Event Paths Example

This non-normative section should be updated so that a flat tree would include slots.

Let's re-use the same composed tree of node trees used in the flattening example section. Suppose that an event is dispatched on node I. The event path will be:

[I, H, O, T, S, R, N, J, C, A] (For the purpose of the explanation, Window is not shown here. The actual event path contains Window.)

It's worth pointing out that if we exclude all nodes which don't participate in the flat tree from the event path, the result would be equivalent to the inclusive ancestors of the node I in the flat tree.

The relationship between the flat tree and an event path. If we exclude O, T, R and J, that don't participate in the flat tree, from the event path, the result would be equivalent to the inclusive ancestors of the node, I, in the flat tree.

Note that the get the parent algorithm associated with Node is designed to achieve the following goals:

  1. If there is a node, CHILD, in the event path and CHILD has a parent node, PARENT, in the node tree, the event path always includes PARENT. PARENT always appears somewhere after CHILD in the event path.
  2. Nodes in the event path form a linear ancestor chain in each node tree. There are no branch points in each node tree.
>
The relationship between an event path and node trees. In the figure, a number shown in a right-side of each node represents a zero-based position of each node in the event path. A parent node always has a larger number than that of its child node in each node tree.

A local event path for each node tree would be seen as:

node tree Local Event Path
document tree 1 [I, H, C, A]
shadow tree 1 [O, N, J]
shadow tree 2 [T, S, R]

That means, if your concern is only one node tree, you can forget all other node trees. The event path would be seen as if the event happened only on the node tree you are focusing on. This is an important aspect in a sense that hosting a shadow tree doesn't have any effect to the local event path as long as the event is not stopped somewhere in the descendant trees.

If you are a web author and your concern is only a document tree, this might be a good news because an event listener that is registered somewhere on the document tree would continue to work even when you attach a shadow root to an element in the document tree to enhance the element. At the same time, an author of a shadow tree also can receive an event which will happen on a node in the document tree, if the node, or its ancestor, is assigned to a slot in the shadow tree.

Event Retargeting

Event target Retargeting

The value of the Event object's target attribute must be the result of the retargeting algorithm with the event's currentTarget and original target value, before adjusted, as input. The result is called a relative target.

The retargeting algorithm must be equivalent to processing the following steps:

Input
BASE, a base node for which a target node should be adjusted
TARGET, a target node which should be adjusted
Output
RELATIVE-TARGET, a relative target, the result of adjusting TARGET for BASE
  1. For each ANCESTOR in TARGET's shadow-including inclusive ancestors, in from-descendants-to-ancestors order:
    1. If ANCESTOR's root is not a shadow root or ANCESTOR's root is BASE's shadow-including inclusive ancestor, return ANCESTOR.
  2. Return null

Event retargeting is a process of computing relative targets for each ancestor of the node at which the event is dispatched. The event target retargeting process must occur prior to dispatch of an event. In other words, any DOM mutation occurred in an event listener does not have any affect on the result of retargeting process.

The motivation of retargeting is to maintain an encapsulation in the cases where event path is across multiple node trees. The event's target might not be an unclosed node at some of nodes in the event path without retargeting. A relative target is a unclosed node that most accurately represents the target of a dispatched event at each node in the event path.

Event relatedTarget Retargeting

Some events have a relatedTarget property, which holds a node that's not the event's target, but is related to the event.

The value of the Event object's relatedTarget attribute must be the result of the retargeting algorithm with the event's currentTarget and relatedTarget as input. The result is called a relative related target.

The event relatedTarget retargeting process must occur prior to dispatch of an event.

Touch Events Retargeting

The Touch target [[!TOUCH-EVENTS]] attribute must be adjusted in the same way as an event with a relatedTarget. Each Touch target in the TouchList returned from TouchEvent touches(), changedTouches() and targetTouches() must be the result of the retargeting algorithm with a current target and Touch target as input.

Event Retargeting Example

Suppose we have a user interface for a media controller, represented by this tree, composed of both document tree and the shadow trees. In this example, we will assume that selectors are allowed to cross the shadow boundaries and we will use these selectors to identify the elements. Also, we will invent a fictional shadow-root element to demarcate the shadow boundaries and represent shadow roots:

  <div id="player">
      <shadow-root id="player-shadow-root">
          <div id="controls">
              <button id="play-button">PLAY</button>
              <input type="range" id="timeline">
                  <shadow-root id="timeline-shadow-root">
                      <div id="slider-thumb" id="timeline-slider-thumb"></div>
                  </shadow-root>
              </input>
              <div id="volume-slider-container">
                  <input type="range" id="volume-slider">
                      <shadow-root id="volume-shadow-root">
                          <div id="slider-thumb" id="volume-slider-thumb"></div>
                      </shadow-root>
                  </input>
              </div>
          </div>
      </shadow-root>
  </div>
          

Let's have a user position their pointing device over the volume slider's thumb (#volume-slider-thumb), thus triggering a mouseover event on that node. For this event, let's pretend it has no associated relatedTarget.

Per the retargeting algorithm, we should have the following set of ancestors and relative targets:

Ancestor Relative Target
#player #player
#player-shadow-root #volume-slider
#controls #volume-slider
#volume-slider-container #volume-slider
#volume-slider #volume-slider
#volume-shadow-root #volume-slider-thumb
#volume-slider-thumb #volume-slider-thumb

After we dispatch the mouseover event using these newly computed relative targets, the user decides to move their pointing device over the thumb of the timeline (#timeline-slider-thumb). This triggers both a mouseout event for the volume slider thumb and the mouseover event for the timeline thumb.

Let's see how the relatedTarget value of the volume thumb's mouseout event is affected. For this event, the relatedTarget is the timeline thumb (#timeline-slider-thumb). Per the relatedTarget retargeting, we should have the following set of ancestors and adjusted related targets:

Ancestor Relative Target Relative Related Target
#player #player #player
#player-shadow-root #volume-slider #timeline
#controls #volume-slider #timeline
#volume-slider-container #volume-slider #timeline
#volume-slider #volume-slider #timeline
#volume-shadow-root #volume-slider-thumb #timeline
#volume-slider-thumb #volume-slider-thumb #timeline

The node, #player, has both target and relatedTarget being the same value (#player), which means that we do not dispatch the event on this node and its ancestors.

Event Dispatch

At the time of event dispatch:

Upon completion of the event dispatch, the Event object's target and relatedTarget must be to the highest ancestor's relative target and relative related target, respectively. Since it is possible for a script to hold on to the Event object past the scope of event dispatch, this step is necessary to avoid revealing the nodes in shadow trees.

The mutation event types must never be dispatched in a shadow tree.

User Interaction

Ranges and Selections

Selection [[!EDITING]] is not defined. Implementation should do their best to do what's best for them. Here's one possible, admittedly naive way:

Since nodes which are in the different node trees never have the same root, there may never exist a valid DOM range that spans multiple node trees.

Accordingly, selections may only exist within one node tree, because they are defined by a single range. The selection, returned by the window.getSelection() method never returns a selection within a shadow tree.

The getSelection() method of the shadow root object returns the current selection in this shadow tree.

Focus

A shadow host can delegate focus to its shadow root by assigning a boolean delegatesFocus flag to be true in ShadowRootInit dictionary. If omitted, a shadow host does not delegate focus to its shadow root, and the shadow host itself can be focusable.

When a shadow host HOST delegates focus, user agent must behave as follows.

  1. In sequential focus navigation, HOST itself will be skipped. See the next secition for the formal definition.
  2. When HOST is focused by focus() method or autofocus attribute: The first focusable area in focus navigation order of HOST's shadow root's focus navigation scope gets focus. See the next section for the formal definition of the ordering.
  3. When mouse is clicked on a node in HOST's shadow tree and the node is not a focusable area: The first focusable area in focus navigation order of HOST's shadow root's focus navigation scope gets focus. See the next section for the formal definition of the ordering.
  4. When any element in HOST's shadow tree has focus, :focus pseudo-class applies to HOST in addition to the focused element itself.
  5. If :focus pseudo-class applies to HOST, and HOST is in a shadow root of another shadow host HOST2 which also delegates focus, :focus pseudo-class applies to HOST2 as well.

Sequential Focus Navigation

focus navigation scope is a set of elements in a shadow-including document. An element belongs to at most one focus navigation scope.

focus navigation scope owner is a node that owns a focus navigation scope. A document, a shadow root, or a slot element can be a focus navigation scope owner.

document sequential focus navigation order is an order of all of the focusable areas in a shadow-including document, reachable by sequential focus navigation.

When a shadow-including document is given, the document sequential focus navigation order is determined by the following steps:

Step 1.

INPUT
DOCUMENT, a composed document
OUTPUT
OWNERS, a set of focus navigation scope owner nodes
  1. Let OWNERS be an empty set.
  2. For each node tree TREE in DOCUMENT:
    1. For each node NODE in TREE, in tree order:
      1. If NODE is a document, a shadow root, or a slot element, append it to OWNERS.

Step 2.

INPUT
DOCUMENT, a composed document
OWNERS, a set of focus navigation scope owner nodes from Step 1
OUTPUT
SCOPEs, a set of focus navigation scopes each of which is an ordered list of elements
SCOPE-MAP, a map from each focus navigation scope owner to its corresponding focus navigation scope
  1. For each owner OWNER in OWNERS:
    1. Let SCOPE be empty list.
    2. Append SCOPE to SCOPE-MAP[OWNER].
  2. For each node tree TREE in DOCUMENT, in shadow-including tree order:
    1. For each ELEMENT in TREE:
      1. Let CURRENT be ELEMENT.
      2. Repeat the following steps until the algorithm stops.
      3. If CURRENT is a child of a shadow host:
        1. If CURRENT is assigned to any slot SLOT, append ELEMENT to SCOPE-MAP[SLOT].
        2. Otherwise do not append ELEMENT to any scope.
        3. Stop this algorithm.
      4. If CURRENT is a slot element and not equal to ELEMENT:
        1. If CURRENT has any assigned nodes, do not append ELEMENT to any scope.
        2. Otherwise append ELEMENT to SCOPE-MAP[CURRENT].
        3. Stop this algorithm.
      5. If CURRENT is a child of a root node (a shadow root or document) ROOT:
        1. Append ELEMENT to SCOPE-MAP[ROOT].
        2. Stop this algorithm.
      6. Otherwise:
        1. Set CURRENT to the parent element of CURRENT.

Step 3.

INPUT
SCOPE, a focus navigation scope
OUTPUT
NAVIGATION-ORDER, an ordered list of elements which should be visited.
  1. For each scope SCOPE:
    1. Let NAVIGATION-ORDER be an empty list.
    2. For each element ELEMENT in a focus navigation scope SCOPE,
      1. if ELEMENT is focusable, a shadow host, or a slot element, append ELEMENT to NAVIGATION-ORDER.
    3. Reorder NAVIGATION-ORDER according to the tabindex value attached to each node. In this step, an element whose tabindex value is negative must not be appended to NAVIGATION-ORDER.

Step 4.

Apply the following focus navigation order merging algorithm with document’s focus navigation order as input. The result is the document sequential focus navigation order.

INPUT
NAVIGATION-ORDER, an ordered list of elements.
OUTPUT
MERGED-NAVIGATION-ORDER, an ordered list of elements.
  1. Let MERGED-NAVIGATION-ORDER be an empty list.
  2. For each element ELEMENT in NAVIGATION-ORDER:
    1. If ELEMENT is a shadow host:
      1. Unless its shadow root’s delegatesFocus flag is set, append ELEMENT to MERGED-NAVIGATION-ORDER.
      2. Apply the focus navigation order merging algorithm with the focus navigation order owned by its shadow root as input, then append the result to MERGED-NAVIGATION-ORDER.
    2. If ELEMENT is a slot element:
      1. Apply the focus navigation order merging algorithm with the focus navigation order owned by the slot element as input, then append the result to MERGED-NAVIGATION-ORDER.
    3. Otherwise:
      1. Append ELEMENT to MERGED-NAVIGATION-ORDER.
    4. Return MERGED-NAVIGATION-ORDER.

For directional focus navigation [[!CSS3-UI]], it is up to the user agent to integrate the shadow trees into the document's directional focus navigation.

Active Element

DocumentOrShadowRoot object's activeElement must be the result of the retargeting algorithm with the context object and the focused element as input, if the result and the context object are in the same tree. Otherwise, null.

Editing

The value of the contenteditable attribute must not propagate from shadow host to its shadow trees.

Assistive Technology

User agents with assistive technology traverse the flat tree, and thus enable full use of WAI-ARIA [[!WAI-ARIA]] semantics in the shadow trees.

Hit Testing

When a text node is a child node of a shadow root, a hit testing must target the shadow host if the text node is the result of the hit testing.

User-agent mouse events must be targeted to the parent node in the flat tree of a text node if the topmost event target is the text node.

This section eventually needs to be part of some general hit testing specification.

HTML Elements in Shadow Trees

Inertness of HTML Elements in a shadow tree

Comparatively, a shadow tree can be seen as somewhere between just part of a document and itself being a document fragment. Since it is rendered, a shadow tree aims to retain the traits of a typical tree in a document. At the same time, it is an encapsulation abstraction, so it has to avoid affecting the document tree. Thus, the HTML elements must behave as specified [[!HTML]] in the shadow trees, with a few exceptions.

According to the [[!HTML]], some HTML Elements would have different behavior if they participate in a shadow tree, instead of a document tree, because their definitions require the elements to be in a document as a necessary condition for them to work. In other words, they shouldn't work if they participate in a shadow tree, even when they are in a shadow-including document. We must fill this gap because we expect that most of HTML Elements behave in the same way as in a document, as long as they are in a shadow-including document. See W3C Bug 26365 and Bug 27406 for the details. The following is the tentative summary of the discussions in the W3C bugs. We, however, haven't covered all HTML Elements and their behaviors here yet. For HTML Elements which are not explicitly stated here, they should be considered as active in a shadow tree. We are trying to update [[!HTML]] itself, instead of having monkey patches here.

HTML Elements are classified into the following categories:

Attributes

When [[!HTML]] defines the processing algorithms to traverse trees for the following attributes, they must use the flat tree.

This list does not include attributes that are defined elsewhere in this specification. Such attributes include:

Other Clarifications

This section is used to state what needs to be clarified. Each clarification will be upstreamed to the HTML Standard or other specifications, eventually, if required.

Document.currentScript must return null if the script element is in a shadow tree. See Issue #477.

Style elements inside a shadow tree must not be able to set the preferred style sheet set for the document tree. Style elements inside a shadow tree should still be applied if it has a title attribute not matching the preferred style sheet set of the document tree. See Issue #391.

An iframe in a shadow tree must not have any effect on window.history neither window.frames. See Issue #184.

:root pseudo class does not match any element if the rule is used in a shadow tree.

Elements and DOM interfaces

Extensions to the DocumentOrShadowRoot Mixin

          partial interface DocumentOrShadowRoot {
            Selection? getSelection ();
            Element? elementFromPoint(double x, double y);
            sequence<Element> elementsFromPoint(double x, double y);
            CaretPosition? caretPositionFromPoint(double x, double y);
            readonly attribute Element? activeElement;
            readonly attribute StyleSheetList styleSheets;
          };
        

The ShadowRoot interface

The ShadowRoot interface represents the shadow root.

readonly attribute Element host

Represents the shadow host which hosts the context object.

On getting, the attribute must return the shadow host which hosts the context object.

[TreatNullAs=EmptyString] attribute DOMString innerHTML
This is similarly defined in Element's innerHTML with the following exceptions:

Because DocumentFragment does not always have a host, innerHTML can not be defined in DocumentFragment.

The nodeType attribute of a ShadowRoot instance must return DOCUMENT_FRAGMENT_NODE. Accordingly, the nodeName attribute of a ShadowRoot instance must return "#document-fragment".

Extensions to Element Interface

ShadowRoot attachShadow(ShadowRootInit shadowRootInitDict)
When invoked, these steps must be run:
  1. If the context object is none of the following elements, throw a NotSupportedError exception.
    • custom element
    • article
    • aside
    • blockquote
    • body
    • div
    • footer
    • h1
    • h2
    • h3
    • h4
    • h5
    • h6
    • header
    • nav
    • p
    • section
    • span

    This list is possible to change. See Issue #110.

  2. If the context object already hosts the shadow tree, throws InvalidStateError exception.
  3. Create a new instance of the ShadowRoot object. The shadowRootInitDict argument allows for setting the mode.
  4. Let the context object host the ShadowRoot object.
  5. Return ShadowRoot object.
readonly attribute HTMLSlotElement? assignedSlot

Represents the assigned slot of the context object.

On getting, the attribute must return the assigned slot of the context object, if there is, and the assigned slot's root's mode is "open". Otherwise must return null.

attribute DOMString slot

Reflects the slot attribute. The slot attribute represents the slot name of a slot to where this element is assigned.

readonly attribute ShadowRoot? shadowRoot

Represents the shadow root that context object hosts.

On getting, the attribute must return the shadow root that context object hosts if there is and its mode is "open". Otherwise must return null.

ShadowRootInit dictionary

required ShadowRootMode mode
Specifies the associated mode of ShadowRoot
boolean delegatesFocus = false
Specifies whether shadow host delegates focus to its ShadowRoot. If omitted, the default value is false.

ShadowRootMode enum

open
Specifies "open" mode
closed
Specifies "closed" mode

Extensions to Text Interface

readonly attribute HTMLSlotElement? assignedSlot

Represents the assigned slot of the context object.

On getting, the attribute must return the assigned slot of the context object, if there is, and the assigned slot participates in an open shadow tree. Otherwise must return null.

The slot element

The slot element is used to define a location of a slot.

Context
Where flow content is expected.
Content model
Transparent
Children
Anything as fallback content
Content attributes
Global attributes
name, the slot name
Represents the slot name.
DOM Interface
attribute DOMString name
Must reflect the name attribute.
sequence<Node> assignedNodes(optional AssignedNodesOptions options)
When invoked, it must return a sequence consisting of either the assigned nodes or the distributed nodes of the context object. If the optional options is given and its flatten is true, the distributed nodes must be returned. Otherwise, the assigned nodes must be returned.

AssignedNodesOptions dictionary

boolean flatten = false

Specifies whether assignedNodes() returns assigned nodes or distributed nodes

Extensions to EventInit Dictionary

boolean scoped = false

Specifies the scoped flag of Event

Extensions to Event Interface

sequence<EventTarget> deepPath()

When invoked, it must return return a sequence consisting of event targets, that must be equivalent to processing the following steps:

Input
EVENT, a context object
Output
FILTERED-PATH, an array of event targets
  1. If EVENT has not been dispatched or EVENT is no longer dispatched, let FILTERED-PATH be an empty array.
  2. Otherwise:
    1. Let PATH be the Event's event path.
    2. Let FILTERED-PATH be the empty ordered list.
    3. Let CURRENT-TARGET-NODE be the result of find the node algorithm with EVENT's current target and PATH.
    4. For each TARGET in PATH:
      1. Let TARGET-NODE be the result of find the Node algorithm with TARGET and PATH.
      2. If both CURRENT-TARGET-NODE and TARGET-NODE exist,
        1. If TARGET-NODE is an unclosed node of the CURRENT-TARGET-NODE, append TARGET to FILTERED-PATH. Otherwise, do nothing
      3. Otherwise:
        1. append TARGET to FILTERED-PATH.

The find the node algorithm given a EVENT-TARGET and PATH are as follows:

  1. For each ITEM in the sub list of PATH, from EVENT-TARGET, inclusive, to the last item of PATH:
    1. If ITEM is a Node, return ITEM.
  2. Return null.
readonly attribute boolean scoped

Returns the scoped flag.

Shadow DOM Example

Bob was asked to turn a simple list of links into a News Widget, which has links organized into two categories: breaking news and just news. The current document markup for the stories looks like this:

<ul class="stories">
    <li><a href="//example.com/stories/1">A story</a></li>
    <li><a href="//example.com/stories/2">Another story</a></li>
    <li class="breaking" slot="breaking"><a href="//example.com/stories/3">Also a story</a></li>
    <li><a href="//example.com/stories/4">Yet another story</a></li>
    <li><a href="//example.com/stories/5">Awesome story</a></li>
    <li class="breaking" slot="breaking"><a href="//example.com/stories/6">Horrible story</a></li>
</ul>
      

It's weird that there are slot attributes in this markup because Bob has not decided to use Shadow DOM yet.

To organize the stories, Bob decides to use shadow DOM. Doing so will allow Bob to keep the document markup uncluttered, and harnessing the power of insertion point makes sorting stories by class name a very simple task. After getting another cup of Green Eye, he quickly mocks up the following shadow tree, to be hosted by the ul element:

<div class="breaking">
    <ul>
        <slot name="breaking"></slot> <!-- slot for breaking news -->
    </ul>
</div>
<div class="other">
    <ul>
        <slot></slot> <!-- slot for the rest of the news -->
    </ul>
</div>
      

Bob then styles the newborn widget according to comps from the designer by adding this to the shadow tree mockup:

<style>
    div.breaking {
        color: Red;
        font-size: 20px;
        border: 1px dashed Purple;
    }
    div.other {
        padding: 2px 0 0 0;
        border: 1px solid Cyan;
    }
</style>
      

While pondering if his company should start looking for a new designer, Bob converts the mockup to code:

function createStoryGroup(className, slotName)
{
    var group = document.createElement('div');
    group.className = className;
    // Empty string in slot name attribute or absence thereof work the same, so no need for special handling.
    group.innerHTML = '<ul><slot name="' + slotName + '"></slot></ul>';
    return group;
}

function createStyle()
{
    var style = document.createElement('style');
    style.textContent = 'div.breaking { color: Red;font-size: 20px; border: 1px dashed Purple; }' +
        'div.other { padding: 2px 0 0 0; border: 1px solid Cyan; }';
    return style;
}

function makeShadowTree(storyList)
{
    var root = storyList.attachShadow({mode: 'open'});
    root.appendChild(createStyle());
    root.appendChild(createStoryGroup('breaking', 'breaking'));
    root.appendChild(createStoryGroup('other', ''));
}

document.addEventListener('DOMContentLoaded', function() {
    [].forEach.call(document.querySelectorAll('ul.stories'), makeShadowTree);
});
      

Well done, Bob! With the cup of coffee still half-full, the work is complete. Recognizing his awesomeness, Bob returns to teaching n00bs the ways of Splatoon.

Acknowledgements

David Hyatt developed XBL 1.0, and Ian Hickson co-wrote XBL 2.0. These documents provided tremendous insight into the problem of functional encapsulation and greatly influenced this specification.

Alex Russell and his considerable forethought triggered a new wave of enthusiasm around the subject of shadow DOM and how it can be applied practically on the Web.

Dominic Cooney, Hajime Morrita, and Roland Steiner worked tirelessly to scope the problem of functional encapsulation within the confines of the Web platform and provided a solid foundation for this document.

The editor would also like to thank Alex Komoroske, Anne van Kesteren, Brandon Payton, Brian Kardell, Darin Fisher, Eric Bidelman, Deepak Sherveghar, Edward O'Connor, Elisée Maurer, Elliott Sprehn, Erik Arvidsson, Glenn Adams, Jonas Sicking, Koji Ishii, Malte Ubl, Mike Taylor, Oliver Nightingale, Olli Pettay, Rafael Weinstein, Richard Bradshaw, Ruud Steltenpool, Sam Dutton, Sergey G. Grekhov, Shinya Kawanaka, Tab Atkins, Takashi Sakamoto, and Yoshinori Sano for their comments and contributions to this specification.

This list is too short. There's a lot of work left to do. Please contribute by reviewing and filing bugs—and don't forget to ask the editor to add your name into this section.