I'm trying to use https://material-ui.com/ components inside shadow dom, and need a way to inject those styles inside shadow dom. by default material-ui
, which uses jss
under the hood injects styles in the head of the page.
Is that even possible? Can anyone come with an example?
The element to which shadow DOM is attached is known as the host. To style the host, use the :host selector. Inheritable properties of the host element will inherit down the shadow tree, where they apply to the shadow children.
The ShadowRoot interface of the Shadow DOM API is the root node of a DOM subtree that is rendered separately from a document's main DOM tree. You can retrieve a reference to an element's shadow root using its Element.
Shadow root: The root node of the shadow tree. Real Example: example of a "video" element,All you see in the DOM is the "video" element, but it contains a series of buttons and other controls inside its shadow DOM.
The shadow root is a document fragment that is attached to the host element and it has a host property that identifies its host element. The act of attaching a shadow root is how the element gets its shadow DOM.
This is what my web component looks like, it is a web component that renders a react app that contains material-ui styles.
import * as React from 'react';
import { render } from 'react-dom';
import { StylesProvider, jssPreset } from '@material-ui/styles';
import { create } from 'jss';
import { App } from '@myApp/core';
class MyWebComponent extends HTMLElement {
connectedCallback() {
const shadowRoot = this.attachShadow({ mode: 'open' });
const mountPoint = document.createElement('span');
const reactRoot = shadowRoot.appendChild(mountPoint);
const jss = create({
...jssPreset(),
insertionPoint: reactRoot
});
render(
<StylesProvider jss={jss}>
<App />
</StylesProvider>,
mountPoint
);
}
}
customElements.define('my-web-commponent', MyWebComponent);
Setting the insertionPoint
on jss to the actual react root inside the shadow root will tell jss to insert those styles inside that shadow root.
Using https://github.com/Wildhoney/ReactShadow to create shadow dom (you could also do it by hand as shown in previous answer), I created a small WrapperComponent that encapsulates the logic.
import root from 'react-shadow';
import {jssPreset, StylesProvider} from "@material-ui/styles";
import {create} from 'jss';
import React, {useState} from "react"
const WrappedJssComponent = ({children}) => {
const [jss, setJss] = useState(null);
function setRefAndCreateJss(headRef) {
if (headRef && !jss) {
const createdJssWithRef = create({...jssPreset(), insertionPoint: headRef})
setJss(createdJssWithRef)
}
}
return (
<root.div>
<head>
<style ref={setRefAndCreateJss}></style>
</head>
{jss &&
<StylesProvider jss={jss}>
{children}
</StylesProvider>
}
</root.div>
)
}
export default WrappedJssComponent
Then you just need to Wrap your app, or the part of your app you want to shadow inside <WrappedJssComponenent><YourComponent></YourComponent></WrappedJssComponenent>
.
Be careful, some of the material-UI component won't work as usual (I had some trouble with
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With