SHadow dom
by Gustavo Medina
@thegoosie
some challenges when...
- Creating a libraries, frameworks, embed widgets
- Duplicate IDs
- Unintentional styling
- Hiding implementation details
Encapsulation
-
Creates a boundary between your code and its client
- NOT PRESENT ON THE WEB...
- except with <iframe>s :(
Web Components
-
Templates (chunks of inert markup)
-
Decorators (no spec as of 2/3/2014)
-
Shadow DOM (encapsulation of a DOM subtree)
-
Custom Elements (devs create their own elements)
-
Imports (packaging and delivering all of the above)
shadow dom: The basics
- Just a sub-tree of DOM nodes
- Subtrees can be associated with an element
- scoped id's and styles
- mark up is encapsulated
- subtree is rendered instead of the element's child nodes
- subtree does not appear as a child of the element
shadow dom is rendered!
let's create some shadows
<template id="shadow">
<div class="shadow-container">
Hello Shadow World!
</div>
</template>
<div id="shadow-host">Hello World!</div>
<script type="text/javascript">
var shadowHost = document.querySelector('#shadow-host'),
shadowRoot = shadowHost.createShadowRoot(),
template = document.querySelector('#shadow');
shadowRoot.appendChild(template.content.cloneNode(true));
</script>
insertion points part 1
- <content></content> (insertion point)
- shadow host's content is projected into the insertion point (distributed content)
<template id="shadow">
<div class="shadow-container">
<h2>Hello <content></content>!</h2>
</div>
</template>
<div id="shadow-host">World</div>
INSERTION POINTS PART 1.5: Select
- Insertion points as a declarative API!!!
<template id="shadow">
<div class="shadow-container">
<h1>
Hello <content select=".world"></content>
from <content select=".location"></content>
</h1>
<div><content select="span"></content></div>
<div><content select="*"></content></div>
</div>
</template>
<div id="shadow-host">
<span class="world">Mundo</span>
<span class="location">Nueva York</span>
<span>Bogota</span>
<span>New Jersey</span>
<div>this is other stuff</div>
</div>
insertion points part 2
- Nesting Shadow DOMS with <shadow></shadow>
Let's style some shadows
- styles are encapsulated
- distributed content keep styles
CSS SELECTORS
- :host(.foo) - targets and style the shadow host
- ^ (hat) and ^^ (cat) - descendant selectors
- cross shadow dom boundaries!!!!!
- document.querySelector('foo ^ bar');
- Pseudo Elements
- ::content
- <div part="foo-bar"></div>
- #shadow-host::part(foo-bar) //in the page
SHADOW DOM style properties
false - default. Keeps inheriting CSS props true - resets props at shadow boundary
true - author styles are applied to Shadow DOM elements (relative to the shadow root)
A word on javascript
JS is NOT encapsulated! Business as usual (except a few cases)
- can't traverse DOM inside a <content>
- some events do not cross the shadow DOM boundaries
INTERESTING PROPS/Methods
- hostElment.shadowRoot;
- root.olderShadowRoot; //if you had a <shadow>
- contentEl.getDistributedNodes(); //<content>
- distributedEl.getDestinationInsertionPoints(); //any distributed element
Event retargeting
- retarget to look like event source is host element
- except events originated in a distributed node
- some event do not cross the shadow boundary
- abort, error, select, change, load, reset, resize, scroll, selectstart
Questions???
@thegoosie
https://github.com/gmedina/penumbra
thanks!
Into The Shadows
By Gustavo Medina
Into The Shadows
An introduction to the Shadow DOM.
- 682