Hint
Encapsulated DOM subtree — styles and JS don't leak in or out; foundation of Web Components
// Attach a shadow root to any element
const host = document.getElementById('my-widget');
const shadow = host.attachShadow({ mode: 'open' }); // or 'closed'
// Add content — fully encapsulated
shadow.innerHTML = `
<style>
/* This CSS is SCOPED to shadow DOM only */
p { color: red; font-size: 1.5rem; }
:host { display: block; border: 1px solid blue; }
</style>
<p>I'm in shadow DOM</p>
<slot></slot> <!-- slot: renders host element's children -->
`;
// 'open' mode: accessible via element.shadowRoot
host.shadowRoot.querySelector('p'); // works
// 'closed' mode: host.shadowRoot = null (truly private)
// <slot> — project host children into shadow DOM
// <my-card><h2>Title</h2></my-card>
// The <h2> is rendered where <slot> is placed
// Web Component using Shadow DOM
class MyButton extends HTMLElement {
constructor() {
super();
const shadow = this.attachShadow({ mode: 'open' });
shadow.innerHTML = `
<style>button { background: purple; color: white; }</style>
<button><slot>Click me</slot></button>
`;
}
}
customElements.define('my-button', MyButton);