Missing styles when using React with Web Components

Viewed 545

I'm creating a widget module that will then be assembled into a bundle and connected to the static sites in a single file. One of the main problems is applying the styles of the parent sites to the widget module. Because of this, an attempt was made to encapsulate the widget using the shadow dom.

import React from 'react';
import ReactDOM from 'react-dom';
import styled from 'styled-components';

const StyledButton = styled.button`...`;
 
function ModuleComponent() {
  return (
    <div>
      <StyledButton>I does not work</StyledButton>
      <button style={{ height: 40, color: "red" }}>It works</button>
    </div>
  );
}
 
class IncapsulatedReactWidgetElement extends HTMLElement {
  connectedCallback() {
    const mountPoint = document.createElement("div");
    this.attachShadow({ mode: "open" }).appendChild(mountPoint);
 
    ReactDOM.render(<ModuleComponent />, mountPoint);
  }
}
 
customElements.define(
  "incapsulated-react-widget-element",
  IncapsulatedReactWidgetElement
);
 
function Root() {
  return <incapsulated-react-widget-element />;
}
 
const MOUNT_NODE = document.getElementById("root");
ReactDOM.render(<Root />, MOUNT_NODE);

Actually it works as expected except the styles. I'm trying to use styled components but nothing works expect inline styles. As you can see, I do two render actions: first for integration ModuleComponent into custom element and second - for render the app. In which way styles can get lost?

1 Answers

Correct way for applying styles is using Style Hook for React. Make use of makeStyles and useStyles and its an standard way of doing it. This may help for quick start: https://material-ui.com/styles/basics/#hook-api

The inline styles that you have used are also kinda a subset of it.

import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button';

const useStyles = makeStyles({
  root: {
    background: 'linear-gradient(45deg, #FE6B8B 30%, #FF8E53 90%)',
    border: 0,
    borderRadius: 3,
    boxShadow: '0 3px 5px 2px rgba(255, 105, 135, .3)',
    color: 'white',
    height: 48,
    padding: '0 30px',
  },
});

export default function Hook() {
  const classes = useStyles();
  return <Button className={classes.root}>Hook</Button>;
}

if you are going to have larger stylesheets, then we can separate it to different file. For site wide changes, you can use createStyle hook.

Related