Copyright © 2016 W3C® (MIT, ERCIM, Keio, Beihang). W3C liability, trademark and permissive document license rules apply.
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.
Shadow DOM specification is being upstreamed to DOM Standard [WHATWG-DOM], HTML Standard [HTML], CSS Scoping Module Level 1 [css-scoping-1], UI Events specification [uievents], and other relevant specifications. This specification may not accurately reflect the latest conclusion. See Issue #377 for details.
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/.
This document was published by the Web Platform Working Group as a Working Draft. This document is intended to become a W3C Recommendation. If you wish to make comments regarding this document, please send them to public-webapps@w3.org (subscribe, archives). All comments are welcome.
Publication as a Working Draft does not imply endorsement by the W3C Membership. This is a draft document and may be updated, replaced or obsoleted by other documents at any time. It is inappropriate to cite this document as other than work in progress.
This document was produced by a group operating under the 5 February 2004 W3C Patent Policy. 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.
This document is governed by the 1 September 2015 W3C Process Document.
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:
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.
This section is a copy of Shadow tree in [WHATWG-DOM]. This section is expected to be synced with that periodically.
A shadow tree is a node tree whose root is a shadow root.
A shadow root is always attached to another node tree through its host. A shadow tree is therefore never alone. The node tree of a shadow root’s host is sometimes referred to as the light tree.
A shadow tree’s corresponding light tree can be a shadow tree itself.
An element is connected if its shadow-including root is a document.
A shadow tree contains zero or more elements that are slots.
A slot has an associated name (a string). Unless stated otherwise it is the empty string.
Use these attribute change steps to update a slot’s name:
If element is a slot, localName is name
, and namespace is null, then:
If value is oldValue, then return.
If value is null and oldValue is the empty string, then return.
If value is the empty string and oldValue is null, then return.
If value is null or the empty string, then set element’s name to the empty string.
Otherwise, set element’s name to value.
Run assign slotables for a tree with element’s tree.
The first slot in a shadow tree, in tree order, whose name is the empty string, is sometimes known as the "default slot".
A slot has an associated assigned nodes (a list of slotables). Unless stated otherwise it is empty.
Element
and Text
nodes are slotables.
A slotable has an associated name (a string). Unless stated otherwise it is the empty string.
Use these attribute change steps to update a slotable’s name:
If localName is slot
and namespace is null, then:
If value is oldValue, then return.
If value is null and oldValue is the empty string, then return.
If value is the empty string and oldValue is null, then return.
If value is null or the empty string, then set element’s name to the empty string.
Otherwise, set element’s name to value.
If element is assigned, then run assign slotables for element’s assigned slot.
Run assign a slot for element.
A slotable has an associated assigned slot (null or a slot). Unless stated otherwise it is null. A slotable is assigned if its assigned slot is non-null.
To find a slot for a given slotable slotable and an optional open flag (unset unless stated otherwise), run these steps:
If slotable’s parent is null, then return null.
Let shadow be slotable’s parent’s shadow root.
If shadow is null, then return null.
If the open flag is set and shadow’s mode is not "open
", then return null.
Return the first slot in shadow’s tree whose name is slotable’s name, if any, and null otherwise.
To find slotables for a given slot slot, run these steps:
Let result be an empty list.
If slot’s root is not a shadow root, then return result.
For each slotable child of host, slotable, in tree order, run these substeps:
Let foundSlot be the result of finding a slot given slotable.
If foundSlot is slot, then append slotable to result.
Return result.
To find flattened slotables for a given slot slot, run these steps:
Let result be an empty list.
Let slotables be the result of finding slotables given slot.
If slotables is the empty list, then append each slotable child of slot, in tree order, to slotables.
For each node in slotables, run these substeps:
If node is a slot, run these subsubsteps:
Let temporaryResult be the result of finding flattened slotables given node.
Append each slotable in temporaryResult, in order, to result.
Otherwise, append node to result.
Return result.
To assign slotables, for a slot slot with an optional suppress signaling flag (unset unless stated otherwise), run these steps:
Let slotables be the result of finding slotables for slot.
If suppress signaling flag is unset, and slotables and slot’s assigned nodes are not identical, then run signal a slot change for slot.
Set slot’s assigned nodes to slotables.
For each slotable in slotables, set slotable’s assigned slot to slot.
To assign slotables for a tree, given a tree tree and an optional set of slots noSignalSlots (empty unless stated otherwise), run these steps for each slot slot in tree, in tree order:
Let suppress signaling flag be set, if slot is in noSignalSlots, and unset otherwise.
Run assign slotables for slot with suppress signaling flag.
To assign a slot, given a slotable slotable, run these steps:
Let slot be the result of finding a slot with slotable.
If slot is non-null, then run assign slotables for slot.
Each unit of related similar-origin browsing contexts has a signal slot list (a list of slots). Unless stated otherwise it is empty. [HTML]
To signal a slot change, for a slot slot, run these steps:
This section is a copy of Mutation algorithms in [WHATWG-DOM]. This section is expected to be synced with that periodically.
To ensure pre-insertion validity of a node into a parent before a child, run these steps:
Document
, DocumentFragment
, or Element
node, throw a HierarchyRequestError
.
HierarchyRequestError
.
NotFoundError
.
DocumentFragment
, DocumentType
, Element
, Text
, ProcessingInstruction
, or Comment
node, throw a HierarchyRequestError
.
Text
node and parent is a document, or node is a doctype and parent is not a document, throw a HierarchyRequestError
.
HierarchyRequestError
.
DocumentFragment
node
Text
node child.
Otherwise, if node has one element child and either parent has an element child, child is a doctype, or child is not null and a doctype is following child.
To pre-insert a node into a parent before a child, run these steps:
Specifications may define insertion steps for all or some nodes. The algorithm is passed insertedNode, as indicated in the insert algorithm below.
To insert a node into a parent before a child, with an optional suppress observers flag, run these steps:
DocumentFragment
node, and one otherwise.
DocumentFragment
node, and a list containing solely node otherwise.
DocumentFragment
node, remove its children with the suppress observers flag set.
DocumentFragment
node, queue a mutation record of "childList
" for node with removedNodes nodes.
This step intentionally does not pay attention to the suppress observers flag.
For each node in nodes, in tree order, run these substeps:
Insert node into parent before child or at the end of parent if child is null.
If parent is a shadow host and node is a slotable, then assign a slot for node.
If parent is a slot whose assigned nodes is the empty list, then run signal a slot change for parent.
Run assign slotables for a tree with node’s tree and a set containing each inclusive descendant of node that is a slot.
For each shadow-including inclusive descendant inclusiveDescendant of node, in shadow-including tree order, run these subsubsteps:
Run the insertion steps with inclusiveDescendant.
If inclusiveDescendant is connected, then:
If inclusiveDescendant is custom, then enqueue a custom element callback reaction with inclusiveDescendant, callback name "connectedCallback
", and an empty argument list.
Otherwise, try to upgrade inclusiveDescendant.
If this successfully upgrades inclusiveDescendant, its connectedCallback
will be enqueued automatically during the upgrade an element algorithm.
childList
" for parent with addedNodes nodes, nextSibling child, and previousSibling child’s previous sibling or parent’s last child if child is null.
To append a node to a parent, pre-insert node into parent before null.
To replace a child with node within a parent, run these steps:
Document
, DocumentFragment
, or Element
node, throw a HierarchyRequestError
.
HierarchyRequestError
.
NotFoundError
.
DocumentFragment
, DocumentType
, Element
, Text
, ProcessingInstruction
, or Comment
node, throw a HierarchyRequestError
.
Text
node and parent is a document, or node is a doctype and parent is not a document, throw a HierarchyRequestError
.
HierarchyRequestError
.
DocumentFragment
node
Text
node child.
Otherwise, if node has one element child and either parent has an element child that is not child or a doctype is following child.
The above statements differ from the pre-insert algorithm.
Let previousSibling be child’s previous sibling.
If child’s parent is not null, run these substeps:
Set removedNodes to a list solely containing child.
Remove child from its parent with the suppress observers flag set.
The above can only be false if child is node.
DocumentFragment
node, and a list containing solely node otherwise.
childList
" for target parent with addedNodes nodes, removedNodes removedNodes, nextSibling reference child, and previousSibling previousSibling.
To replace all with a node within a parent, run these steps:
DocumentFragment
node, and a list containing node otherwise.
childList
" for parent with addedNodes addedNodes and removedNodes removedNodes.
This algorithm does not make any checks with regards to the node tree constraints. Specification authors need to use it wisely.
To pre-remove a child from a parent, run these steps:
NotFoundError
.
Specifications may define removing steps for all or some nodes. The algorithm is passed removedNode, and optionally oldParent, as indicated in the remove algorithm below.
To remove a node from a parent, with an optional suppress observers flag, run these steps:
For each NodeIterator
object iterator whose root’s node document is node’s node document, run the NodeIterator
pre-removing steps given node and iterator.
If node is assigned, then run assign slotables for node’s assigned slot.
If parent is a slot whose assigned nodes is the empty list, then run signal a slot change for parent.
If node has an inclusive descendant that is a slot, then:
Run assign slotables for a tree with parent’s tree.
Run assign slotables for a tree with node’s tree and a set containing each inclusive descendant of node that is a slot.
Run the removing steps with node and parent.
If node is custom, then enqueue a custom element callback reaction with node, callback name "
disconnectedCallback
", and an empty argument list.
For each shadow-including descendant descendant of node, in shadow-including tree order, run these substeps:
Run the removing steps with descendant.
If descendant is custom, then enqueue a custom element callback reaction with descendant, callback name "
disconnectedCallback
", and an empty argument list.
subtree
is true, then for each such registered observer registered, append a transient registered observer whose observer and options are identical to those of registered and source which is registered to node’s list of registered observers.
childList
" for parent with removedNodes a list solely containing node, nextSibling oldNextSibling, and previousSibling oldPreviousSibling.
This section is a copy of Dispatching events section in [WHATWG-DOM]. This section is expected to be synced with that periodically.
To dispatch an event to a target, with an optional legacy target override flag, 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.
If target is relatedTarget and target is not event’s relatedTarget, then return true.
Append (target, targetOverride, relatedTarget) to event’s path.
Let isActivationEvent be true, if event is a MouseEvent
object and event’s type
attribute is "click
", and false otherwise.
Let activationTarget be target, if isActivationEvent is true and target has activation behavior, and null otherwise.
Let parent be the result of invoking target’s get the parent with event.
While parent is non-null:
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 (parent, null, relatedTarget) to event’s path.
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 (parent, target, relatedTarget) to event’s path.
If parent is non-null, then set parent to the result of invoking parent’s get the parent with event.
Set event’s eventPhase
attribute to CAPTURING_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.
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 to AT_TARGET
.
Otherwise, set event’s eventPhase
attribute to BUBBLING_PHASE
.
If either event’s eventPhase
attribute is BUBBLING_PHASE
and event’s bubbles
attribute is true or event’s eventPhase
attribute is AT_TARGET
, then invoke tuple’s item with event.
Unset event’s dispatch flag, stop propagation flag, and stop immediate propagation flag.
Set event’s eventPhase
attribute to NONE
.
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.
This section is non-normative.
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.
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.
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.:focus
pseudo-class applies to HOST in addition to the focused element itself.: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.
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.
The value of the contenteditable
attribute must not propagate from shadow host to its shadow trees.
User agents with assistive technology traverse the flat tree, and thus enable full use of WAI-ARIA [WAI-ARIA] semantics in the shadow trees.
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.
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:
Active in a shadow tree
A subset of HTML elements which must behave as if they were in the document tree, even when they participate in a shadow tree, as long as they are in a shadow-including document.
The following HTML elements must be classified to this category:
dialog
iframe
style
Inert in a shadow tree:
A subset of HTML elements which must behave as inert, or not part of the document tree, if they participate in a shadow tree. This is consistent how the HTML elements would behave in a document fragment.
The following HTML elements must be classified to this category:
Inert unless being rendered:
A subset of HTML elements which must behave as inert, or not part of the document tree, unless they are being rendered. In other words, if they don't particitpate in a document flat tree, they must behave as inert.
The following HTML elements must be classified to this category:
applet
embed
object
For example, suppose that an object
element is a child node of a shadow host, but the object
element is not assigned to a slot. In this case, according to the flat tree children calculation algorithm, this element never participate in a document flat tree. Therefore, this element is inert because this element is not being rendered. .
When [HTML] defines the processing algorithms to traverse trees for the following attributes, they must use the flat tree.
dir
draggable
dropzone
hidden
lang
and xml:lang
spellcheck
title
This list does not include attributes that are defined elsewhere in this specification. Such attributes include:
tabindex
is defined in Focus Navigation.role
and ARIA
are defined in Assistive Technology.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.
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;
};
activeElement
, these methods and attributes are defined in the similar way as currently defined in Document, considering only the current node tree.
elementFromPoint
and elementsFromPoints
, they should return the result of running the retargeting algorithm with context object and the original result as input.
styleSheets
, it should return an empty StyleSheetList if the context object is not in a shadow-including document.
ShadowRoot
interface
The ShadowRoot
interface represents the shadow root.
interface ShadowRoot : DocumentFragment {
readonly attribute Element
host;
[TreatNullAs=EmptyString]
attribute DOMString innerHTML;
};
host
of type Element
, readonly Represents the shadow host which hosts the context object.
On getting, the attribute must return the shadow host which hosts the context object.
innerHTML
of type DOMString
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"
.
Element
Interface
partial interface Element {
ShadowRoot
attachShadow (ShadowRootInit
shadowRootInitDict);
readonly attribute HTMLSlotElement
? assignedSlot;
attribute DOMString slot;
readonly attribute ShadowRoot
? shadowRoot;
};
assignedSlot
of type HTMLSlotElement
, readonly , nullableRepresents 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
.
shadowRoot
of type ShadowRoot
, readonly , nullableRepresents 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
.
slot
of type DOMString
Reflects the slot
attribute. The slot
attribute represents the slot name of a slot to where this element is assigned.
attachShadow
NotSupportedError
exception.
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.
InvalidStateError
exception.ShadowRoot
object. The shadowRootInitDict
argument allows for setting the mode.
ShadowRoot
object.ShadowRoot
object.Parameter | Type | Nullable | Optional | Description |
---|---|---|---|---|
shadowRootInitDict |
|
✘ | ✘ |
ShadowRoot
ShadowRootInit
dictionary
dictionary ShadowRootInit {
required ShadowRootMode
mode;
boolean delegatesFocus = false;
};
ShadowRootInit
Members
delegatesFocus
of type boolean, defaulting to false
ShadowRoot
. If omitted, the default value is false.mode
of type ShadowRootMode
, requiredShadowRoot
ShadowRootMode
enum
enum ShadowRootMode {
"open",
"closed"
};
Enumeration description | |
---|---|
open |
Specifies "open" mode |
closed |
Specifies "closed" mode |
Text
Interface
partial interface Text {
readonly attribute HTMLSlotElement
? assignedSlot;
};
assignedSlot
of type HTMLSlotElement
, readonly , nullableRepresents 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
.
slot
element
The slot element is used to define a location of a slot.
name
, the slot nameinterface HTMLSlotElement : HTMLElement {
attribute DOMString name;
sequence<Node> assignedNodes (optional AssignedNodesOptions
options);
};
name
of type DOMStringassignedNodes
flatten
distributed nodesmustassigned nodesmust
Parameter | Type | Nullable | Optional | Description |
---|---|---|---|---|
options |
|
✘ | ✔ |
sequence<Node>
AssignedNodesOptions
dictionary
dictionary AssignedNodesOptions {
boolean flatten = false;
};
AssignedNodesOptions
Members
flatten
of type boolean, defaulting to false
Specifies whether assignedNodes()
returns assigned nodes or distributed nodes
EventInit
Dictionary
partial dictionary EventInit {
boolean scoped = false;
};
EventInit
Members
scoped
of type boolean, defaulting to false
Specifies the scoped flag of Event
Event
Interface
partial interface Event {
sequence<EventTarget> deepPath ();
readonly attribute boolean scoped;
};
scoped
of type boolean, readonly Returns the scoped flag.
deepPath
When invoked, it must return return a sequence consisting of event targets, that must be equivalent to processing the following steps:
The find the node algorithm given a EVENT-TARGET and PATH are as follows:
sequence<EventTarget>
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() {
document.querySelectorAll('ul.stories').forEach(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.
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.