3

I'm developing a wrapper to transpile React components into Web Components. What do I need to apply the styles when the components are rendered in the shadow DOM?.

I am trying to wrap a material-ui react component (Button) in a Web Component, however when I attach the component to the shadow DOM the styles are not applied.

//Wrapper

import ReactDOM,{ render } from 'react-dom';

import Button from '@material-ui/core/Button';

class ButtonWrapper extends HTMLElement {
    constructor() {
        super();
    }
    connectedCallback() {
        const mountPoint = document.createElement('span');
        this.attachShadow({ mode: 'open' }).appendChild(mountPoint);
       ReactDOM.render(
            <Button variant="contained" color="primary">
                Material Button
            </Button>
            , mountPoint);  
    }
}

customElements.define('button-material-wrapper', ButtonWrapper);

//HTML

<button-material-wrapper></button-material-wrapper>

//Webpack.config

...
module: {
            rules: [
                {
                    test: /\.js$/,
                    use: {
                        loader: 'babel-loader',
                        options: { presets: ['@babel/preset-env', '@babel/preset-react'] }
                    }
                },
                {
                    test:/\.(s*)css$/,
                    use: ['style-loader', 'css-loader', 'sass-loader']
                }
            ]
        }
....

Expected output: The material-ui button is correctly rendered

Actual output: The material-ui button is corectly rendered as a child node of the shadow-root but the material styles are not applied.

1 Answer 1

0

In webpack, style-loader helps you to add the style to global document style. But web component can not access the style(including the global material style) outside shadow DOM which result in your Actual output. One solution I found is to use css-to-string-loader to import the string of the scss of material component manually, and then add it to the style of current shadow DOM by hand.

// Webpack.config

{
    test: /.*\.scss$/,
    use: ['css-to-string-loader', 'css-loader', 'sass-loader'],
},

// In Web Component (connectedCallback)

const style = document.createElement('style');
const style.innerHTML = require('@material/xxxx.scss');
const head = document.createElement('head');
head.appendChild(style);
this.attachShadow({ mode: 'open' }).appnedChild(head)

In my opinion, it's not elegant at all, looking forward to a better solution.

Sign up to request clarification or add additional context in comments.

1 Comment

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.