16

TL:DR

How can I get CSS of React components to work inside of a shadow root, while keeping the encapsulation benefits of CSS Modules class? I'd like to insert per-component <style> elements instead of inside of <head> or another arbitrary element.

What I have

I'm currently using CSS Modules in React with a custom Webpack script; [style-loader, css-loader, sass-loader] in the traditional way. The resulting compiled CSS is injected as <style> tags in head.


    // MyComponent.jsx
    import React from 'react';
    import styles from './MyComponent.scss';

    export const MyComponent = () => {
      return <div className={styles.container}>Hello!</div>
    }

    // MyComponent.scss
    .container {
      background: purple;
    }

result

    <!-- rendered page -->
    <head>
      ...
      <style>.myComponent__container__hash123 { background: purple }</style>
    </head>
    <body>
      ...
      <div class="myComponent__container__hash123">Hello!</div>
    </body>

What I want

For use inside of a shadow root, I would like to instead inject each component's compiled CSS into a <style> tag on its root.

    <!-- rendered page -->
    <head>
      ...
    </head>
    <body>
      ...
      <div>
        #shadow-root
          <div class="myComponent__container__hash123">Hello!</div>
          <style>.myComponent__container__hash123 { background: purple }</style>
        #end shadow-root
      </div>
    </body>

What I tried

1. insert

This will not work for component libraries which compile themselves, where I cannot know the end consumer in advance.

2. to-string-loader

https://www.npmjs.com/package/css-to-string-loader

When combined with style-loader, the result is classnames aren't resolved (e.g. styles.container === undefined).


Ideally I would have import styles from './MyComponent' contain the compiled CSS string in addition to classname mapping - however this is not supported as per style-loader docs

Community
  • 1
  • 1
mike-shtil
  • 623
  • 5
  • 13
  • 1
    Have you checked out [react-shade](https://github.com/treshugart/react-shade)? – Ross Allen Dec 27 '19 at 02:41
  • can you tell me why do you need this ? – Amir Rezvani Dec 27 '19 at 05:54
  • @AmirRezvani I'm looking to convert existing React components using CSS Modules for styling to run inside shadowRoots. A straightforward solution would be to have each component come with a self-contained style element. – mike-shtil Dec 29 '19 at 17:21
  • @RossAllen thank you - I'm familiar with react-shade, however AFAIK it requires a rewrite of styling from e.g. CSS Modules (using SCSS in my case) to Styled Components or JS object-based styles. – mike-shtil Dec 29 '19 at 17:23

2 Answers2

0

Two years too late, but:

I'm not quite sure if this is what you want, but in React you can add style directly into JSX like this:

  <style>
    {`
      body {
        font-family: 'Inter', sans-serif;
        font-size: 14px;
        background-color: #151515;
        color: white;
      }
    `}
  </style>

or using your example:

<style>
    {`
      .myComponent__container__hash123 { 
        background: purple;
      }
    `}
</style>
Duke Dougal
  • 24,359
  • 31
  • 91
  • 123
0

You can use Webpack "style-loader" plugin with insert parameter.

          {
            loader: "style-loader",
            options: {
              injectType: "lazyStyleTag",
              insert: function insertIntoTarget(element, options) {
                var parent = options.target || document.head;
                parent.appendChild(element);
              },
            },
          },

Refer to this for more details.

husayt
  • 14,553
  • 8
  • 53
  • 81