Building Components in Shadow DOM
When we decided that every SpiderPublish component would render inside a Shadow DOM boundary, we knew we were trading simplicity for isolation. Six months later, we can say with confidence: it was the right call. Here is what we learned along the way.
Why Shadow DOM
In a multi-tenant CMS, components from different authors coexist on the same page. A header built by Agency A must not break when placed alongside a pricing table built by Agency B. Traditional CSS scoping solutions — BEM, CSS Modules, scoped attributes — all leak under pressure. Shadow DOM is the only browser-native mechanism that provides true style encapsulation.
With Shadow DOM, styles defined inside a component cannot affect elements outside it, and styles from the host page cannot reach inside the component. This is exactly the guarantee we need for a marketplace where hundreds of components from different authors coexist.
The Theme Token System
Pure isolation creates a problem: how do you apply a consistent brand across components from different authors? Our solution is theme tokens — CSS custom properties injected at the :host level that flow into every component.
Each tenant defines their brand through content_settings: primary color, surface color, heading color, body text color. These are compiled into CSS custom properties and injected into every component shadow root at render time. Authors use var(--primary), var(--heading), var(--surface) instead of hardcoded hex values.
Event Handling Across Boundaries
Shadow DOM boundaries stop event propagation for certain event types. Click events bubble through shadow boundaries, but custom events do not by default. We had to explicitly set composed: true and bubbles: true on every custom event dispatched from within a component.
The querySelector Problem
Inside Shadow DOM, document.querySelector cannot see elements within a shadow root. Components must use this.getRootNode().querySelector() to find sibling elements within the same shadow tree, or this.closest() to traverse upward through shadow boundaries.
Lessons Learned
Shadow DOM is not a silver bullet. It adds complexity to event handling, accessibility, and form participation. But for our use case — a marketplace of components from untrusted authors rendering on hundreds of tenant sites — the isolation guarantees are worth every tradeoff. We would make the same choice again.