2

I'm trying to use babel-plugin-react-css-modules in existing React project. Most of components work just fine, however there is a problem with 'passing' style to child components.

I have some parent components like this:

SearchBlock/index.js

import "./style.scss"
import { SettingsIcon } from "../../Icons"
...
<div styleName='SearchBlock'>
   <SettingsIcon size='17' color='#2991F5' />
</div>

SearcBlock/style.scss

.SearchBlock {
  ...

  .SettingsIcon {
     margin-right: 7px;
  }
...
    }

And child components like this

SettingsIcon/index.js

const SettingsIcon = (props) => {
...
    return (
      <svg
        width={size}
        height={size}
        viewBox='0 0 24 24'
        fill='none'
        xmlns='...'
        className='SettingsIcon'
      >
...

So the icon has an appropriate style in different components.

What I get in generated css files:

.src-components-Search-SearchBlock-___style__SearchBlock___2MeUy .src-components-Search-SearchBlock-___style__SettingsIcon___3SWQh {
        margin-right: 7px; }

Seems correct. However, the child element is rendered like this:

<svg ... class="SettingsIcon"><</svg>

instead of

<svg ... class="src-components-Search-SearchBlock-___style__SettingsIcon___3SWQh"><</svg>

I cannot use styleName in settingsIcon because webpack throws error without importing at least one stylesheet.

Is there any way to fix this?


My configuration

webpack.common.js

...
    test: /\.s?css$/,
                use: [
                    {
                      loader: 'style-loader',
                    },
                    {
                      loader: 'css-loader',
                      options: {
                        modules: {
                          mode: 'local',
                          localIdentName: isProd
                          ? '[hash:base64]'
                          : "[path]___[name]__[local]___[hash:base64:5]",
                        },
                        sourceMap: true,
                        importLoaders: 1,
                        onlyLocals: false,
                      },
                    },
                    {
                      loader: 'postcss-loader',
                      options: {
                        sourceMap: true,
                      },
                    },
                    {
                      loader: 'sass-loader',
                      options: {
                        sourceMap: true,
                      },
                    },
                  ],
            },
...

babel.config.js

const isProd = process.env.NODE_ENV === 'production';

function createReactCssModulesPlugin() {
  return [
    "react-css-modules",
    {
      filetypes: {
        ".scss": {
          syntax: "postcss-scss",
          plugins: [
            "postcss-import-sync2",
            [
              "postcss-nested",
              {
                bubble: ["@include"],
                preserveEmpty: true,
              },
            ],
          ],
        },
      },
      generateScopedName: isProd
        ? '[hash:base64]'
        : "[path]___[name]__[local]___[hash:base64:5]",
      webpackHotModuleReloading: isProd ? false : true,
      exclude: "node_modules",
      handleMissingStyleName: isProd ? "throw" : "warn",
      autoResolveMultipleImports: true,
    },
  ];
}

module.exports = function (api) {
  api.cache(true)
  return {
    plugins: ["@babel/transform-react-jsx", createReactCssModulesPlugin()],
  };
};

1 Answer 1

1

8 months have passed and you probably know the answer by now, but I'm gonna post my answer anyway.

SearchBlock/style.scss

.SearchBlock {

  .SettingsIcon {
    margin-right: 7px;
  }
}

SettingsIcon/index.js

const SettingsIcon = (props) => {
  return (
    <svg
      ...
      className='SettingsIcon'
    >

This will not work because your class .SettingsIcon is in the local scope of your component in SearchBlock/index.js

You can either do the styling of SettingsIcon/index.js inside it like so:

SettingsIcon/index.js

import "./style.scss" // style for SettingsIcon

const SettingsIcon = (props) => {
  return (
    <svg
      ...
      styleName='SettingsIcon'
    >
  )
}

or pass the class as a prop like so:

SearchBlock/index.js

import style from "./style.scss"
import { SettingsIcon } from "../../Icons"

<div styleName='SearchBlock'>
 <SettingsIcon size='17' color='#2991F5' extClasses={ style.SettingsIcon }/>
</div>

SettingsIcon/style.scss

.SearchBlock { ... }

.SettingsIcon {
   margin-right: 7px;
}

SettingsIcon/index.js

import "./style.scss" // style for SettingsIcon

const SettingsIcon = (props) => {
  return (
    <svg
    ...
    styleName={ props.extClasses }
    >
  )
}
Sign up to request clarification or add additional context in comments.

Comments

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.