In this post I will describe how to set up CSS modules and SCSS for applications created with create-react-app. When I did it for the first time I found the process quite cumbersome and not well documented so I hope this post will help others avoid the same struggles.

Setting up CSS modules

The first step is obviously to create a new React app by typing create-react-app <app_name> in the terminal. After that let's enter the newly created app directory and eject the config settings via npm run eject.

For the CSS modules part we will use fellow Lithuanian's Gajus Kuizinas Babel plugin babel-plugin-react-css-modules. As per description, it transforms styleName to className using compile time CSS module resolution. If it sounds complicated, don't worry. All it means is that for CSS classes you will have to use styleName attribute instead of className which will automatically be converted to a CSS module compatible class and added as one of the classes.

⚠️Note that as of writing of this post, when you eject configs generated by create-react-app, some dependencies will be missing. Just install them as needed.

To install the Babel plugin, type npm install babel-plugin-react-css-modules --save. After that, in the root of your app's directory create .babelrc file and add the following settings there:

{
  "presets": ["react-app"],
  "plugins": [
    [
      "babel-plugin-react-css-modules"
    ]
  ]
}

Voila! Now when you add styleName attribute to a component it will automagically get converted to a CSS module compatible class. However, if you try adding styleName classes, you will notice that nothing happens and the CSS classes do not get applied. This is because at this point the CSS classes are not yet scoped locally and still use global names. So as the next step we have to adjust our React application production and development configs.

First, open webpack.config.dev.js and add the following options for style-loader:

require.resolve('style-loader'),
{
  loader: require.resolve('css-loader'),
  options: {
    modules: true,
    localIdentName: '[path]___[name]__[local]___[hash:base64:5]',
    importLoaders: 1,
  },
},

Apply similar changes to webpack.config.prod.js but this time directly to the css-loader:

loader: require.resolve('css-loader'),
options: {
  modules: true,
  localIdentName: '[path]___[name]__[local]___[hash:base64:5]',
  importLoaders: 1,
  minimize: true,
  sourceMap: shouldUseSourceMap,
},

Now, try out our setup by replacing default App.js className attributes with styleName attributes:

import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';

class App extends Component {
  render() {
    return (
      <div styleName="App">
        <header styleName="App-header">
          <img src={logo} styleName="App-logo" alt="logo" />
          <h1 styleName="App-title">Welcome to React</h1>
        </header>
        <p styleName="App-intro">
          To get started, edit <code>src/App.js</code> and save to reload.
        </p>
      </div>
    );
  }
}

export default App;

At this point you should see exactly the same screen as before but if you inspect the markup, you will notice that CSS class names have been automatically generated scoping them locally to the component.

Screen-Shot-2018-09-14-at-18.24.19

Setting up SCSS

We are halfway there. While CSS modules is great, I found it lacking in certain respects and wanted to add SCSS for extra functionality. Let's do it!

We will start by installing several packages via npm install node-sass postcss-scss sass-loader --save.

Then we have to adjust our .babelrc settings to the following:

{
  "presets": ["react-app"],
  "plugins": [
    [
      "babel-plugin-react-css-modules",
      {
        "filetypes": {
          ".scss": {
            "syntax": "postcss-scss"
          }
        }
      }
    ]
  ]
}

The above makes sure that .scss filetypes are recognized and proper syntax parser is used.

Then we have to adjust our React app configs. First, both in webpack.config.prod.js and webpack.config.dev.js change test: /\.css$/ to test: /\.scss$/. Then, also in both files, add sass-loader at the end of all loaders via which should look as follows:

{
  loader: 'sass-loader', // compiles Sass to CSS
},

As the final step, rename all files ending with .css to .scss, fix the paths and voila, you are all set, congratulations!

Demo/code

Now, I do realize that there are a lot of steps involved. So to inspect or download all the code in one place check out the GitHub repo for this post.