<div id="host-section" class="host">
<h1 class="title">Title</h1>
<p class="paragraph">Paragraph</p>
</div>
Problems
A component/webview
.host { display: flex; }
.title { font-size: 32px; }
.paragraph { color: red; }
<div id="host-section" class="host">
<AWebView />
<h1 class="title">My Title</h1>
</div>
B component/webview
.host { display: block; }
.title { font-size: 48px !important; }
CSS module can help ?
<div
id="host-section"
class="member_host__8vfa7">
<h1
class="member_title__a783f">
Title
</h1>
<p
class="member_paragraph__913fg">
Paragraph
</p>
</div>
Problems
Member component
.member_host__8vfa7 { display: flex; }
.member_title__a783f { font-size: 32px; }
.member_paragraph__913fg { color: red; }
<div
id="host-section"
class="member_host__3gh8l">
<AWebView />
<h1
class="member_title__a783f">
My Title
</h1>
</div>
Another Member component
.member_host__3gh8l { display: block; }
.member_title__a783f { font-size: 48px !important; }
CSS module can help ?
Problems is that we need an isolated environment for our components
Shadow DOM
<body>
<header>
<h1>Hello DOM</h1>
</header>
</body>
Background on DOM
const header = document.createElement('header');
const h1 = document.createElement('h1');
h1.textContent = 'Hello DOM';
header.appendChild(h1);
document.body.appendChild(header);
=
Document
body
header
h1
head
Hello DOM
(極簡化的 DOM tree)
Create a shadow DOM
const header = document.createElement('header');
const shadowRoot = header.attachShadow({ mode: 'open' });
shadowRoot.innerHTML = '<h1>Hello Shadow DOM</h1>';
Document
body
header
h1
head
Hello DOM
(極簡化的 DOM tree)
Document
body
header
h1
head
Hello Shadow DOM
(極簡化的 DOM tree)
Shadow host (DOM tree 中)
Shadow Root
Shadow Tree
Valid elements we can attachShadow
<img /> ?
Given children is non-sense
<a /> ?
Security reasons
Create a shadow DOM for custom element
// Use custom elements API v1 to register a new HTML tag and define its JS behavior
// using an ES6 class. Every instance of <fancy-tab> will have this same prototype.
customElements.define('fancy-tabs', class extends HTMLElement {
constructor() {
super(); // always call super() first in the constructor.
// Attach a shadow root to <fancy-tabs>.
const shadowRoot = this.attachShadow({mode: 'open'});
shadowRoot.innerHTML = `
<style>#tabs { ... }</style> <!-- styles are scoped to fancy-tabs! -->
<div id="tabs">...</div>
<div id="panels">...</div>
`;
}
...
});
<fancy-tabs>
#shadow-root(open)
<style>#tabs { ... }</style>
<div id="tabs">...</div>
<div id="panels">...</div>
</fancy-tabs>
<fancy-tabs></fancy-tabs>
inside your html, render <fancy-tabs>
Slot
Slots are placeholders inside your component that users can fill with their own markup.
By defining one or more slots, you invite outside markup to render in your component's shadow DOM
CSS :host
This has no effect when used outside a shadow DOM.
<my-component centered>
#shadow-root(open)
<style>
:host { display: flex; }
:host([centered]) { align-items: center; }
</style>
</my-component>
<template>
Holding HTML that is not to be rendered immediately when a page is loaded but may be instantiated subsequently during runtime using JavaScript.
<template id="element-template">
<style>
:host { display: grid; }
.title { font-size: 24px; }
</style>
<h1 class="title">
My Title
</h1>
</template>
<h1 class="title">My Title</h1>
In your .html
In your browser
References