Shadow DOM
The Shadow DOM is the most complicated part of Web Components because they offer a level of encapsulation and isolation that has never existed on the web platform.
html
<custom-alert>
<p>This is Light DOM content</p>
-----------Shadow DOM-------------
| <img src="path/to/icon.svg"/> |
| <slot></slot> |
| <button>Close</button> |
----------------------------------
</custom-alert><custom-alert>
<p>This is Light DOM content</p>
-----------Shadow DOM-------------
| <img src="path/to/icon.svg"/> |
| <slot></slot> |
| <button>Close</button> |
----------------------------------
</custom-alert>The Shadow DOM behaves a lot like an <iframe>, but better. Styling and scripting that happens within the Shadow DOM does not spill outside of its "shadow boundary". But three critical differences from an <iframe> are:
- The Shadow DOM templates render as first-party content on the page.
- You avoid all the variable height issues related with
<iframe>content. - Interacting with (open) Shadow DOM is much easier and doesn't have the
postMessageworkarounds or related security issues that exist with<iframe>.
Attaching a Shadow Root
js
class CustomAlert extends HTMLElement {
constructor() {
super();
this.attachShadow({
mode: 'open'|'closed' // default: 'closed'
delegatesFocus: true|false // default: false
})
}
}class CustomAlert extends HTMLElement {
constructor() {
super();
this.attachShadow({
mode: 'open'|'closed' // default: 'closed'
delegatesFocus: true|false // default: false
})
}
}Shadow Roots have two modes
open: Exposes thecustomElement.shadowRootto external JavaScriptclosed:customElement.shadowRootreturnsnullto external JavaScript.
Appending a <template>
js
const myTemplate = document.createElement('template')
myTemplate.innerHTML = `<div>Hello, world!</div>`;
class CustomAlert extends HTMLElement {
constructor() {
super();
this._shadowRoot = this.attachShadow({ mode: 'open' })
this._shadowRoot.appendChild(myTemplate.content.cloneNode(true))
}
}const myTemplate = document.createElement('template')
myTemplate.innerHTML = `<div>Hello, world!</div>`;
class CustomAlert extends HTMLElement {
constructor() {
super();
this._shadowRoot = this.attachShadow({ mode: 'open' })
this._shadowRoot.appendChild(myTemplate.content.cloneNode(true))
}
}Resources
- Shadow DOM on MDN
- Web components: from zero to hero by Pascal Schilp