Search code examples
reactjswebpacksasscss-modulesreact-css-modules

Module scss ampersand class selector not working


I have a simple scss file with

.navItem {
  cursor: pointer;
    
  &.active {
    color: $primaryPurple;
  }
    
  &:hover {
    color: $primaryPurple;
  }
    
  span {
    margin-left: 10px;
  }
}

For some reason, the :hover works but .active doesn't work. As you can see in the image below, li clearly has the active class but I don't see the font color css changed.

enter image description here


Solution

  • TL;DR: Pass the name as a JavaScript Object, not like a simple string.

    Actually, this issue comes from the css-modules configuration. Obviously, based on the AdminSideBar_navItem__1aFBc in the embed picture. your css-modules configuration in the Webpack config is:

    // webpack config
    
    module.exports = {
      ~~~
      module: {
        ~~~
    
        rules: [
          {
            test: /\.scss$/,
            use: ExtractTextPlugin.extract({
              fallback: 'style-loader',
              use: [
                {
                  loader: 'css-loader',
                  options: {
                    modules: true,
                    importLoaders: 1,
                    localIdentName: '[name]_[local]_[hash:base64:5]', // <=== Attention to this line
                    sourceMap: true,
                  }
                },
                ~~~
              ],
           }),
        ],
      },
      ~~~
    };
    

    So, when you are using css-modules it means you will have so professional advantages like a more compressed css bundle file or full hashed unreadably uglified bundle. for these benefits, you should use CSS class names like a JavaScript object, pay attention to the following ReactJS code alongside using css-modules:

    import React from 'react';
    import cn from 'classnames'; // <=== install it to have easy coding
    import styles from '[pathToScssFiles]/styles.scss';
    
    const MyComponent = ({ isActive }) => (
      <li className={cn(styles.navItem, isActive && styles.active)} />
    );
    
    

    I hope, you understand my point, you passed the styles.active as a simple string: "active". so css-modules cannot get your class name as an object and pass it exactly like what it got, as a simple string, hence, "active" **BUT** in the CSS bundle file the css-modulesuse the'[name][local][hash:base64:5]'` pattern to deform its name.

    Your :hover should work and it works because anyone cannot change it, it's a pseudo-class.

    For sure, write a weird property for .active:

    .navItem {
      cursor: pointer;
        
      &.active {
        fill: yellow;
      }
    

    Now seek for the fill: yellow in the CSS bundle that Webpack makes for you. you see it is:

    .AdminSideBar_navItem__1aFBc .AdminSideBar_active__9be2a {
      fill: yellow;
    }
    

    Note: the ~~~ means etc.