Skip to content

Instantly share code, notes, and snippets.

@georgiee
Created June 20, 2022 14:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save georgiee/e0fb109d1e6a2ed4d663cdebf675123b to your computer and use it in GitHub Desktop.
Save georgiee/e0fb109d1e6a2ed4d663cdebf675123b to your computer and use it in GitHub Desktop.
web component lite for react: isolate css & dom (shadow dom enhancement)

I'm building a React widget where I don't control the environment. I want to make sure that no css bleeds into my widget. Instead of delviering my component as a web component I though of the underlying shadow dom standard to render react directly into a shadow dom (together with any styles emitted from styled components).

Works pretty good. Idea is from https://www.wpeform.io/blog/render-react-app-shadow-dom-styled-components/ which I found while searching for some prior art of this approach.

// Instead of rendering directly into your root element
const root = createRoot(element);
root.render(<App config={config}/>);
// You can render into a shadow element DOM
const root = createRootWithShadowDom(element);
root.render(<App config={config}/>);
import { createRoot } from 'react-dom/client';
import { StyleSheetManager } from 'styled-components';
import React from 'react';
/**
* Render a given React app plus the styled component styles inside a shadow dom
* to prevent any styles bleeding into our component.
*
* Idea from https://www.wpeform.io/blog/render-react-app-shadow-dom-styled-components/
* Thank you ✨
*
* I wrapped the approach in a convenient function to easily render any root wrapped by a shadow dom.
*/
export const createRootWithShadowDom = (element) => {
const shadow = element.attachShadow({ mode: 'open' });
const styleSlot = document.createElement('section');
const renderIn = document.createElement('div');
shadow.appendChild(styleSlot);
styleSlot.appendChild(renderIn);
const root = createRoot(shadow);
return {
render: (children) => {
root.render(
<StyleSheetManager target={styleSlot}>
{children}
</StyleSheetManager>
)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment