Shadow Root
A reusable widget can require style isolation so its styles do not affect the surrounding document and document styles do not affect the widget.
The browser’s Shadow DOM provides this isolation with a separate DOM tree. Retend exposes it through the <ShadowRoot> component.
Using ShadowRoot
Wrap the content to isolate in <ShadowRoot>. Import it from retend-web, because it is browser-specific.
import { ShadowRoot } from 'retend-web'; function Card() { return ( <div class="card-container"> <ShadowRoot> <p>This content lives inside an isolated shadow DOM!</p> </ShadowRoot> </div> ); }
<ShadowRoot> attaches to its parent <div>. Content inside it is isolated from the surrounding document.
Escaping Global Styles
The Shadow DOM isolates the elements it contains, so a <style> element inside the shadow root applies within that shadow root rather than to the rest of the document.
import { ShadowRoot } from 'retend-web'; function StyledComponent() { return ( <div> <div class="test">I turn blue because of the global stylesheet.</div> <ShadowRoot> {/* This style ONLY applies inside this ShadowRoot */} <style>{'.test { color: red; }'}</style> <div class="test">I am completely isolated and my text is red.</div> </ShadowRoot> </div> ); }
The global .test class does not affect the inner div, and the inner <style> does not change the outer div.
Reactivity and Features
The HTML is isolated from the rest of the page, but Retend’s component behavior remains available across the shadow boundary:
- Reactivity: You can use Cells and control flow functions (
If,For) naturally. - Context and Scopes: Context from
createScope()flows down through the shadow boundary perfectly. - Events: Event listeners like
onClickwork right out of the box.
import { Cell } from 'retend'; import { ShadowRoot } from 'retend-web'; function IsolatedToggle() { const isOn = Cell.source(false); return ( <div class="toggle-host"> <ShadowRoot> <style> {` button { padding: 0.5rem 1rem; background-color: #007bff; color: white; border-radius: 4px; } `} </style> <p>Status: {isOn}</p> <button type="button" onClick={() => isOn.set(!isOn.get())}> Toggle </button> </ShadowRoot> </div> ); }
Important Rules
When using <ShadowRoot>, follow these rules:
- It must be inside an HTML element: The
<ShadowRoot>attaches to its direct parent. That parent must be a standard HTML element (like a<div>,<section>, or<article>). - Only one per parent: You should never place two
<ShadowRoot>components directly inside the exact same parent element.