Implementing a CSS Sandbox for Qiankun: Shadow DOM and Scoped CSS Isolation

This article explains how to build a CSS sandbox for Qiankun micro‑frontends by using Shadow DOM for strict style isolation and a Scoped CSS approach for experimental isolation, providing step‑by‑step code examples, underlying principles, and a final Web Component implementation.

Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Implementing a CSS Sandbox for Qiankun: Shadow DOM and Scoped CSS Isolation

The article begins with a brief introduction, stating that it will demonstrate how to create a CSS sandbox for Qiankun, complementing a previous tutorial on a JavaScript sandbox.

Preparation

Three files are required: index.html (the entry HTML), shadowDOMIsolation.js (Shadow DOM sandbox implementation), and scopedCSSIsolation.js (Scoped CSS sandbox implementation). The source code is hosted in the mini-css-sandbox repository.

Shadow DOM Sandbox

Principle

Shadow DOM attaches a hidden, independent DOM tree to a regular DOM element (the shadow host), providing hard style isolation.

Implementation

The shadowDOMIsolation function trims the HTML string, creates a container div, extracts the root element, clears its content, attaches a shadow root (using attachShadow({mode:'open'}) or the legacy createShadowRoot), injects the original inner HTML into the shadow root, and returns the element.

function shadowDOMIsolation(contentHtmlString) {
  // Clean HTML
  contentHtmlString = contentHtmlString.trim();

  // Create container div
  const containerElement = document.createElement('div');
  containerElement.innerHTML = contentHtmlString;

  // Get root div element
  const appElement = containerElement.firstChild;

  const { innerHTML } = appElement;
  appElement.innerHTML = '';

  let shadow;
  if (appElement.attachShadow) {
    // Modern API
    shadow = appElement.attachShadow({ mode: 'open' });
  } else {
    // Legacy API
    shadow = appElement.createShadowRoot();
  }

  // Populate shadow DOM
  shadow.innerHTML = innerHTML;

  return appElement;
}

The resulting effect shows that external styles (e.g., a global red p style) do not affect the content inside the shadow DOM.

Scoped CSS Sandbox

Principle

Scoped CSS extracts the <style> text from a micro‑app and rewrites each selector by prefixing it with a unique container selector such as div[data-app-name="MyApp"], ensuring the styles apply only within that container.

Implementation

The core functions are: processCSS(appElement, stylesheetElement, appName) – creates a temporary disabled <style> element to obtain CSS rules, then rewrites them using rewrite. ruleStyle(rule, prefix) – replaces the selector part of a CSS rule with the prefixed selector. rewrite(rules, prefix) – iterates over CSS rules, handling STYLE rules (others like MEDIA and SUPPORTS are omitted for brevity).

function processCSS(appElement, stylesheetElement, appName) {
  const prefix = `${appElement.tagName.toLowerCase()}[data-app-name="${appName}"]`;
  const tempNode = document.createElement('style');
  document.body.appendChild(tempNode);
  tempNode.sheet.disabled = true;

  if (stylesheetElement.textContent !== '') {
    const textNode = document.createTextNode(stylesheetElement.textContent || '');
    tempNode.appendChild(textNode);
    const sheet = tempNode.sheet;
    const rules = [...sheet?.cssRules ?? []];
    stylesheetElement.textContent = this.rewrite(rules, prefix);
    tempNode.removeChild(textNode);
  }
}

function scopedCSSIsolation(appName, contentHtmlString) {
  contentHtmlString = contentHtmlString.trim();
  const containerElement = document.createElement('div');
  containerElement.innerHTML = contentHtmlString;
  const appElement = containerElement.firstChild;
  appElement.setAttribute('data-app-name', appName);
  const styleNodes = appElement.querySelectorAll('style') || [];
  [...styleNodes].forEach((stylesheetElement) => {
    processCSS(appElement, stylesheetElement, appName);
  });
  return appElement;
}

A test case demonstrates that the outer text remains red while the inner text becomes blue after the scoped CSS transformation.

Turning It Into a Web Component

To avoid repetitive container handling, the article wraps the isolation logic into a custom element isolation-content. The component reads data-app-name and data-isolation-mode attributes, builds the inner HTML, applies either shadowDOMIsolation or scopedCSSIsolation based on the mode, clears its original content, and appends the isolated element.

class Isolation extends HTMLElement {
  constructor() {
    super();
    const name = this.getAttribute('data-app-name');
    const mode = this.getAttribute('data-isolation-mode');
    const html = `<div class="wrapper">${this.innerHTML.trim()}</div>`;
    const appElement = mode === 'shadowDOM' ? shadowDOMIsolation(html) : scopedCSSIsolation(name, html);
    this.innerHTML = '';
    this.appendChild(appElement);
  }
}

customElements.define('isolation-content', Isolation);

The final HTML includes the three script files ( scopedCSSIsolation.js, shadowDOMIsolation.js, and Isolation.js) and demonstrates both isolation modes side by side.

Summary

Qiankun style isolation offers two methods: Shadow DOM isolation (hard isolation) and Scoped CSS isolation (selector prefixing).

Shadow DOM leverages the browser's native shadow tree to completely separate styles.

Scoped CSS rewrites <style> rules by adding a unique container selector, achieving isolation without a shadow tree.

Both techniques can be encapsulated into a reusable Web Component for cleaner micro‑frontend integration.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Micro FrontendsShadow DOMScoped CSSCSS sandboxWeb Component
Rare Earth Juejin Tech Community
Written by

Rare Earth Juejin Tech Community

Juejin, a tech community that helps developers grow.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.