Hayato Ito [email protected]
This document summarizes what "Shadow DOM v1" means and its status in Blink.
Last update: <2015-11-12 Thu>
Shadow DOM is one of the pieces of Web Components. Numerous online resources about Web Components are available. I recommend http://webcomponents.org/, which is well-maintained.
What is Shadow DOM v1? Does v represents for version? I thought that Shadow DOM spec is "Living Standard".
Shadow DOM spec should be considered as Living Standard. HTML Standard and DOM Standard have already adapted Living Standard model.
You could read v1
as version 1, however, please don't take it seriously. We, browser vendors, need a good terminology which represents something on which all of us can agree to implement Shadow DOM.
v1
is a convenient term in a discussion.
If you are uncomfortable with v1
, you can think it as p1
, priority 1. I am using v1
label for an issue if the issue must be resolved asap so other browser vendors can start to implement Shadow DOM.
There is no extra meaning with v1
other than that.
Relevant Links:
- The resolution of the Web Components f2f meeting, April 2015
- Shadow DOM v1 Open Issues
- The state of Web Components from Mozilla
As you can imagine, there is no significant meaning for v2
label. I am using v2
label for a spec issue if the issue doesn't need to be resolved soon.
You can consider v2
as "fix it later". v2
is also a convenient term in the discussion because we are already using v1
.
We can say something like: "Let's defer it to v2 since we can consider it later".
Now I'm focusing on solving all Shadow DOM v1 issues because it might block other vendors to implement Shadow DOM.
In short:
- Shadow DOM
v0
: Supported. Blink shipped Shadow DOM in M35. Let me call what Blink is shipping nowv0
so we can distinguish it fromv1
.v0
will be deprecated once Blink supportsv1
. - Shadow DOM
v1
: In development.- "Intent to Implement: Shadow DOM v1" thread in blink-dev
TODO(hayato): This list is incomplete as of 2015-10-09. Update the list and add more links for details.
-
Removed:
- Element.createShadowRoot()
<content>
,<shadow>
- Multiple Shadow Roots
- Shadow piecing descendant combinator,
/deep/
and shadow pseudo elements,::shadow
-
Added:
- attachShadow (<= createShadowRoot was renamed to)
- Disallow attachShadow() for some elements.
- Closed Shadow Trees
- Slots
- NonDocumentTypeChildNode.assignedSlot
- Slot.getAssignedNodes()
- Event.deepPath (<= Event.path was renamed to)
-
On-going discussion which might affect both
v0
andv1
- Cascading order for Shadow Trees
- Events dispatching model. Only trusted events are subject to the event path trimming algorithm.
- Event.scoped
- The return type of getDistributedNodes() will change, from NodeList to sequence.
WARNING: Regarding with a date, the following is a very rough estimate and is likely to change. I hope I could give you more precise schedule after I finish to implement the prototype of v1.
A tentative schedule to deprecate Shadow DOM v0 is:
-
[2015 Q3 (Done at M45)] Deprecate Multiple Shadow Roots
-
[2015 Q3 (Done at M45)] Deprecate
/deep/
and::shadow
-
[2016 Q1] Finish the implementation of Shadow DOM v1 (guarded by
ShadowDOMV1
runtime flag) so user can experiment v1 in Blink.-
TODO(hayato): Decide the mandatory features of v1 which we should ship at first. Some of the features can be implemented later as long as an interoperability risk is low.
-
[2016 Q2] Ship (the essential parts of) Shadow DOM v1 in Blink
- TODO(hayato): What's the criteria of shipping? How can we make sure that the spec is stable enough?
-
Wait for major libraries, such as Polymer, to switch to use Shadow DOM v1 and be shipped.
-
[2016 Q4 or later] Send an "Intent to Deprecate: Element.createShadowRoot()" to blink-dev.
- TODO(hayato): Deprecate all v0 related APIs together?
- e.g. Deprecate
event.path
at this timing?
- e.g. Deprecate
- TODO(hayato): Deprecate all v0 related APIs together?
-
[2017 or later] Send an "Intent to Remove: Shadow DOM v0" to blink-dev if we can feel it's ready to remove.
How v0
and v1
can interact each other in the transition period? It looks they can not be used at the same time in the same document.
In the transition period from v0
to v1
, it is highly expected that one document would happen to mix web components based on v0
and web components based on `v1. Users might want to mix third-party libraries in their web pages.
To support such a situation, I've decided to support both, v0 and v1, co-exist in the same document in Blink.
Because the Shadow DOM spec is inappropriate place to explain how v0 and v1 interact each other, let me explain its behavior, as an unofficial spec, here.
Disclaimer: This is a tentative plan. If I encounter a technical difficulty to support both in the same document, I might change the plan. In any cases, I'll do the best effort to continue to support v0 in the transition time even after v1
comes to Blink.
###Rule 1) A V0 shadow tree, created by createShadowRoot
, supports only an insertion point (<content>
), but it doesn't support a slot.
###Rule 2) A v1 shadow tree, created by attachShadow
, supports only a slot (<slot>
), but it doesn't support an insertion point.
What this means is:
- A
<slot>
element in v0 shadow tree never behave as a slot. That would behave as if it were a HTMLUnknownElement. - A
<content>
element in v1 shadow tree never behave as an insertion point. That would behave as if it were a HTMLUnknownElement.
Example: <slot>
is used in v0 shadow tree (You shouldn't do that!):
[document tree]
<div id=host1>
<div id="a" slot="slotA">
[shadow tree 1] // a child tree of document tree, created by host1.createShadowRoot()
<shadow-root>
<slot name="slotA"> // This doesn't work as intended. Don't use <slot> in v0 shadow tree.
<content select="#a"> // This works as intended. #a is distributed to this insertion point.
Example: <content>
is used in v1 shadow tree. (You shouldn't do that!):
[document tree]
<div id=host1>
<div id="a" slot="slotA">
[shadow tree 1] // a child tree of document tree, created by host1.attachShadow(..)
<shadow-root>
<slot name="slotA"> // This works as intended. #a is assigned to this slot.
<content select="#a"> // This doesn't work as intended. Don't use <content> in v1 shadow tree.
I hope this is a reasonable restriction for most users.
By introducing this simple restriction, we don't have to remember the order of precedence in selecting nodes if both <slot>
and <content>
are used in in the same shadow tree.
###Rule 3) A tree of trees supports a distribution across v0 and v1 shadow trees, called an unified distribution.
Let's explain what this means by examples.
Example): The parent tree is a v0 shadow tree, and the child tree is a v1 shadow tree.
[document tree]
<div id=host1>
<div id="a">
[shadow tree 1] // a child tree of document tree, created by host1.createShadowRoot()
<shadow-root>
<div id=host2>
<content id="c" select="#a" slot="slotA">
[shadow tree 2] // a child tree of shadow tree 1, created by host2.attachShadow(..)
<shadow-root>
<slot id="s" name="slotA">
The distribution would be:
c.getDistributedNodes == [a] // As usual
c.assignedSlot == s // content can be assigned to a slot. This won't be surprising.
// s.getDistributedNodes != [c]
s.getDistributedNodes == [a] // If a <content> is assigned to a slot, <content> would act like a *slot*.
a.getDestinationInsertionPoints == [c, s] // A slot *can* appear in the getDestinationInsertionPoints. It would behave as if it were an insertion point.
Example): The parent tree is a v1 shadow tree, and the child tree is a v0 shadow tree.
[document tree]
<div id=host1>
<div id="a" slot="slotA">
[shadow tree 1] // a child tree of document tree, created by host1.attachShadow(..)
<shadow-root>
<div id=host2>
<slot id="s" slot="slotA">
[shadow tree 2] // a child tree of shadow tree 1, created by host2.createShadowRoot()
<shadow-root>
<content id="c" select="#a">
The distribution would be:
a.assignedSlot == s
s.getDistributedNodes == [a] // As usual
c.getDistributedNodes == [a] // <content> will select a node from the distributed nodes of a slot, not a slot itself. In general, <content select="slot"> doesn't make sense in most scenes.
a.getDestinationInsertionPoints == [s, c] // A node can be re-distributed through a slot.
-
I'd like to remove ElementShadow and relevant classes someday. However, we can't remove it until we drop the support of multiple shadow roots from Blink.
- Note that Blink just deprecated the multiple shadow roots. We are still supporting it. - I'm afraid that Blink will have painful period since we have to support both worlds for a while. I'm looking for the best approach which makes our codebase manageable and competitive.
-
A StyleResolver can be simplified somehow hopefully, given that
/deep/
and::shadow
are gone and the Cascading Order for Shadow Tress will be simplified.- There is an on-going effort to make Style Resolver more factored and get benefits from scopes style resolving. - Note that we have still `::content`. The situation mightn't change as I thought.
-
I'm adding one more kind of ShadowRoot, called ClosedShadowRoot, as a different ShadowRoot than UA ShadowRoot.
- I've renamed `{Author,UserAgent}ShadowRoot` to `{Open,Closed}ShadowRoot` in the [CL](https://codereview.chromium.org/935283002), however, it turned out that the name of `ClosedShadowRoot` caused a lot of confusion to our codebase. So, instead of batch renaming, I'll introduce the name of "closed" in a more incremental way so that `ClosedShadowRoot` and `UserAgentShadowRoot` can co-exist, with the different meanings, which doesn't upset the existing code. - See the [revert patch](https://codereview.chromium.org/1091473002/) for details.