Slots Shadow Dom Average ratng: 6,4/10 3990 reviews

Shadow DOM is a new DOM feature that helps you build components. You can think of shadow DOM as ascoped subtree inside your element.

Read more on Web Fundamentals. This document gives an overview of shadow DOM as it relates toPolymer. For a more comprehensive overview of Shadow DOM, seeShadow DOM v1: self-contained web componentson Web Fundamentals.

Consider a header component that includes a page title and a menu button: The DOM tree for thiselement might look like this:

Shadow DOM lets you place the children in a scoped subtree, so document-level CSS can't restyle thebutton by accident, for example. This subtree is called a shadow tree.

Slots Without Shadow Dom

Right now the logic goes like: if you're slotted, traverse your slots and collect rules in their shadow trees as needed. This is the code This is nice because the complexity of styling the element depends directly on the complexity of the shadow trees that you're building, and it only affects slotted nodes. The shadow DOM specification includes a means for allowing content from outside the shadow root to be rendered inside of our custom element. For those of you who remember AngularJS, this is a similar concept to ng-transclude or using props.children in React. With Web Components, this is done using the element. Shadow DOM provides a way to scope CSS styles to a specific DOM subtree and isolate that subtree from the rest of the document. The element gives us a way to control where the children of a Custom Element should be inserted within its Shadow Tree. Shadow DOM is commonly used for CSS encapsulation. However, Shadow DOM has another useful feature called Slots. The Slot API is a content projection API that allows HTML content from the host application to be rendered into your component template. Common examples of this are things like cards and modals.

The shadow root is the top of the shadow tree. The element that the tree is attached to(<my-header>) is called the shadow host. The host has a property called shadowRoot thatrefers to the shadow root. The shadow root has a host property that identifies its host element.

The shadow tree is separate from the element's children. You can think of this shadow tree as partof the component's implementation, which outside elements don't need to know about. Theelement's children are part of its public interface.

You can add a shadow tree to an element imperatively by calling attachShadow:

Polymer provides a declarative mechanism for adding a shadow tree using a DOM template.When you provide a DOM template for an element, Polymer attaches a shadow root for each instance ofthe element and copies the template contents into the shadow tree.

Note that the template includes a <style> element. CSS placed in the shadow tree is scoped to theshadow tree, and won't leak out to other parts of your DOM.

Shadow DOM and composition

Slots without shadow dom

By default, if an element has shadow DOM, the shadow tree is rendered instead of the element'schildren. To allow children to render, you can add a <slot> element to your shadow tree. Thinkof the <slot> as a placeholder showing where child nodes will render. Consider the followingshadow tree for <my-header>:

The user can add children like this:

The header renders as if the <slot> element was replaced by the children:

The element's actual descendant tree is sometime called its light DOM, in contrast to its shadow DOMtree.

The process of turning the light DOM and shadow DOM trees into a single tree for rendering is calledflattening the tree. While the <slot> elements don't render, they are included in theflattened tree, so they can take part in event bubbling, for example.

You can control where a child should be distributed into the flattened tree using named slots.

A named slot only accepts top-level children that have a matching slot attribute:

A slot with no name attribute acts as the default slot for any children that don't have a slotattribute. If a child's slot attribute doesn't match any named slot element in the shadow tree,that child doesn't appear at all.

Slots Shadow Dom

Slots Shadow Domain

For example, consider an example-card element with the following shadow tree:

If the example card is used like this:

The first span is assigned into the title slot. The div, which has no slot attribute, isassigned to the default slot. The final span, which has a slot name that doesn't appear in theshadow tree, doesn't show up in the flattened tree, and doesn't render.

Note that only top-level children can match a slot. Consider the following example:

The <example-card> has two top-level children, both <div> elements. Both are assigned to thedefault slot. The slot attribute on the span has no effect on the distribution, because the spanisn't a top-level child.

Fallback content

A slot can contain fallback content that's displayed when no nodes are assigned to the slot. Forexample:

The user can supply their own icon for the element like this:

If the user omits the icon, the fallback content supplies a default icon:

Multi-level distribution

A slot element may also be assigned to a slot. For example, consider two levels of shadow trees.

Given markup like this:

The flattened tree looks like this:

The ordering may be a little confusing at first. At each level, the light DOM children areassigned to a slot in the host's shadow DOM. The span 'I'm in light DOM' is assigned to theslot #parent-slot in <parent-element>'s shadow DOM. The #parent-slot is then assigned to#child-slot in <child-element>'s shadow DOM.

Note: This example uses id on slots for illustration purposes only. This is not the same asthe name attribute. These slots are unnamed and are therefore default slots.

The slot elements don't render, so the rendered tree is much simpler:

In spec language, a slot's distributed nodes are the assigned nodes, with any slots replaced bytheir assigned nodes or fallback content. So in the example above, #child-slot has onedistributed node, the span. You can think of the distributed nodes as the list of nodes that takethe place of the slot in the rendered tree.

Slots without shadow dom

Slot APIs

Shadow DOM provides a few new APIs for checking distribution:

  • HTMLElement.assignedSlot property gives the assigned slot for an element, or null if theelement isn't assigned to a slot.
  • HTMLSlotElement.assignedNodes method returns the list of nodes associated with a given slot.When called with the {flatten: true} option, returns the distributed nodes for a slot.
  • HTMLSlotElement.slotchange event is fired when a slot's distributed nodes change.

For more details, see Working with slots in JS on Web Fundamentals.

Observe added and removed children

The Polymer.FlattenedNodesObserver class provides utilities to track an element's flattened tree.That is, a list of the node's child nodes, with any <slot> elements replaced by their distributednodes. FlattenedNodesObserver is an optional utility that can be loaded fromlib/utils/flattened-nodes-observer.html.

Polymer.FlattenedNodesObserver.getFlattenedNodes(node) returns a list of flattened nodes forthe specified node.

Use the Polymer.FlattenedNodesObserver class to track when the flattened node list changes.

You pass the FlattenedNodesObserver a callback to be invoked when nodes are added orremoved. The callback takes a single Object argument, with addedNodes andremovedNodes arrays.

The method returns a handle that can be used to stop observation:

A few notes on FlattenedNodesObserver:

  • The callback argument lists added and removed nodes, not just elements.If you're only interested in elements, you can filter the node list:

  • The observer handle also provides a flush method, that can be used for unit testing.

Event retargeting

To preserve the encapsulation of the shadow tree, some events are stopped at the shadow DOM boundary.

Other bubbling events are retargeted as they bubble up the tree. Retargeting adjusts the event'starget so that it represents an element in the same scope as the listening element.

For example, given a tree like this:

If the user clicks on the image element the click event bubbles up the tree:

  • A listener on the image element itself receives the <img> as the target.
  • A listener on the <fancy-button> receives the <fancy-button> as the target, because theoriginal target is inside its shadow root.
  • A listener on the <div> in <example-card>'s shadow DOM also receives <fancy-button> as thetarget, since they are in the same shadow DOM tree.
  • A listener on the <example-card> receives the <example-card> itself as the target.

The event provides a composedPath method that returns an array of nodes that the event will passthrough. In this case, the array would include:

  • The <img> element itself.
  • The shadow root of <fancy-button>.
  • The <div> element.
  • The shadow root of <example-card>.
  • Any ancestors of <example-card> (for example, <body>, <html>, document and Window).

By default, custom events don't propagate though shadow DOM boundaries. To allow a custom eventto travel through a shadow DOM boundary and be retargeted, you need to create it with the composedflag set to true:

For more information on events in shadow trees, see The Shadow DOM event model in the Web Fundamentals article on shadow DOM.

Shadow DOM styling

Styles inside a shadow tree are scoped to the shadow tree, and don't affect elements outside theshadow tree. Styles outside the shadow tree also don't match selectors inside the shadow tree.However, inheritable style properties like color still inherit down from host to shadow tree.

In this example, the <div> has a blue background, even though the div selector is less specificthan the .test selector in the main document. That's because the main document selector doesn'tmatch the <div> in the shadow DOM at all. On the other hand, the white text color set on thedocument body inherits down to <styled-element> and into its shadow root.

There is one case where a style rule inside a shadow tree matches an element outside the shadow tree.You can define styles for the host element, using the :host pseudoclass or the :host()functional pseudoclass.

You can also style light DOM children that are assigned to slots using the ::slotted()pseudoelement. For example, ::slotted(img) selects any image tags that are assigned to slots in theshadow tree.

Domain

For more information, see Styling in the Web Fundamentals article on shadow DOM.

Theming and custom properties

You can't directly style anything in a shadow tree using a CSS rule outside of the shadow tree.The exception is CSS properties (such as color and font) that inherit down the tree. A shadow treeinherits CSS properties from its host.

To let users customize your element, you can expose specific styling properties using CSS customproperties and custom property mixins. Custom properties provide a way to add a styling API to yourelement.

Polyfill limitations. When using polyfilled versions of custom properties and mixins, there area number of limitations you should be aware of. For details, see the Shady CSS README file.

You can think of a custom property as a variable that can be substituted in to your CSS rules:

This sets the host's background color to the value of the --my-theme-color custom property. Anyoneusing your element can set the property at a higher level:

Custom properties inherit down the tree, so a value set at the document level is accessible frominside a shadow tree.

The substitution can include default values to use if no property is set:

The default can even be another var() function:

Custom property mixins

Custom property mixins are a feature built on top of the custom property specification. Basically,the mixin is a variable that contains multiple properties:

A component can import or mix in the entire set of rules using the @apply rule:

The @apply rule has the same effect as adding the contents of --my-custom-mixin inline in theruleset where @apply is used.

Shadow DOM polyfills

Because shadow DOM is not available on all platforms, Polymer takes advantage of the shady DOM andshady CSS polyfills if they're installed. These polyfills are included in the webcomponents-lite.jspolyfill bundle.

These polyfills provide reasonable emulation of native shadow DOM while maintaining good performance.However, there are some shadow DOM features that can't be polyfilled completely. If you'resupporting browsers that don't include native shadow DOM, you need to be aware of these limitations.It's also helpful to understand some details of the shady DOM polyfill when debugging applicationsunder shady DOM.

How the polyfills work

The polyfills use a combination of techniques to emulate shadow DOM:

  • Shady DOM. Maintains the logical divisions of shadow tree and descendant tree internally, sochildren added to the light DOM or shadow DOM render correctly. Patches DOM APIs on affectedelements in order to emulate the native shadow DOM APIs.
  • Shady CSS. Provides style encapsulation by adding classes to shadow DOM children and rewritingstyle rules so that they apply to the correct scope.

The following sections discuss each polyfill in more depth.

Shady DOM polyfill

A browser without native shadow DOM only renders the document and its tree of descendants.

To emulate shadow DOM's rendering of the flattened tree, the shady DOM polyfill has to maintainvirtual children and shadowRoot properties with separate logical trees. Each host element'sactual children—the descendant tree visible to the browser—is a pre-flattened tree of shadow andlight DOM children. The tree you'll see using developer tools looks like the rendered tree, not thelogical tree.

Under the polyfill, the slot elements don't appear in the browser's view of the tree. So unlikenative shadow DOM, slots don't take part in event bubbling.

The polyfill patches existing DOM APIs on nodes that are affected by shadow DOM—that is, nodesare in a shadow tree, nodes that hose a shadow tree, or nodes that are light DOM children of shadowhosts. For example, when you call appendChild on a node with a shadow root, the polyfill adds thechild to a virtual tree of light DOM children, calculates where the child should appear in therendered tree, and then adds it to the actual descendant tree in the correct place.

For more information, see the Shady DOM polyfill README.

Shady CSS polyfill

The Shady CSS polyfill emulates shadow DOM style encapsulation, and also provides emulation for CSScustom properties and custom property mixins.

To emulate encapsulation, the shady CSS polyfill adds classes to elements inside a shady DOM tree.It also rewrites style rules defined inside an element's template so that they're confined to theelement.

Shady CSS does not rewrite style rules in document-level stylesheets. This means that document-levelstyles can leak into shadow trees. However, it provides a custom element, <custom-style> forwriting polyfilled styles outside of an element. This includes support for custom CSS properties andrewriting rules so they don't leak into shadow trees.

For more information, see the Shady CSS polyfill README.

Resources

For further reading:

  • Shadow DOM v1: self-contained web components on Web Fundamentals.
  • Custom properties specification.
  • Custom property mixins proposal.
  • Shady DOM polyfill README.
  • Shady CSS polyfill README.