How to use Sass and CSS Modules with create-react-app

A short yet detailed guide to styling components with create-react-app with Sass and CSS Modules, which now is part of CRA.

Up until the release of create-react-app v2, if you wanted to include Sass or CSS Modules in your project, you would have to eject from create-react-app, learn Webpack configurations, install Sass loaders and configure it yourself.

[topads][/topads]

Not anymore. The team at Facebook released create-react-app v2 and among the many improvements, they gave us the ability to use Sass and CSS Modules right out of the box, and in this tutorial, you will learn how simple it is to include them in your projects using create-react-app.

Let’s create a simple project to demonstrate this.

Getting Sassy with Sass

First, create a new project with the latest create-react-app. I will call mine cra-sass

npx create-react-app cra-sass

Aside: If you are unsure of what npx is, or what it does, basically it uses the latest packages from the npm registry, so you don’t need to have create-react-app locally installed.

You will need one new dependency for Sass support. Install node-sass (inside the cra-sass project)

yarn add sass

Now rename ./scr/App.css to ./src/App.scss.

Once that is done, open ./src/App.js and in line3 you will find import './App.css'. Change it to import './App.scss'

At this point you can run the app

yarn start

You will see the default template created by create-react-app looking good!

CRA Default Template
CRA Default Template

Let’s create another Sass file and name it variables.scss under ./src directory.

Open this newly created Sass file and copy the following

$primary-color: #282c34;
$secondary-color: #61dafb;

Now open App.scss and modify it as follows (updates highlighted)

@import './variables.scss';
.App {
  text-align: center;
}
.App-logo {
  animation: App-logo-spin infinite 20s linear;
  height: 40vmin;
}
.App-header {
  background-color: $primary-color;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  font-size: calc(10px + 2vmin);
  color: white;
}
.App-link {
  color: $secondary-color;
}
@keyframes App-logo-spin {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

As you can see, we are importing variables.scss and the variables we created for the background color and link color.

If you stopped the app, go ahead and run it again (yarn start). If you didn’t stop the app, head over to your browser and you will see the app still looks the same as before. That’s because we just extracted the colors to a separate file

With that in mind, you now have the full power of Sass within create-react-app without the need to eject and losing support for any future updates to the project.

But wait, there is more! When you build the app, create-react-app will use PostCSS with the Autoprefixer plugin to automatically add the required vendor prefixes.

This works with the browsers list in your package.json. By default, create-react-app ships with the following configuration

  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }

These are the browsers that create-react-app is targeting by default.

If you need support for different browsers (say IE 10) you will need to include the specific browser as follows

  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all",
      "ie 10"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }

For a full list of browser queries, head over to the official Browserlist documentation.

One last thing, CSS Grid prefixing is turned off by default. If you need it, you can turn it on by adding /* autoprefixer grid: on */ to the top of your CSS file. However, there are limitations, so familiarize yourself with those.

[signupform][/signupform]

CSS Modules

The team at Facebook made it really easy to use CSS Modules with create-react-app. You just have to use the following naming convention: [name].module.css or [name].module.scss, where [name] is the name of your stylesheet.

Before proceeding with an example, if you are unsure about CSS Modules, here is the official definition from the repo:

A CSS Module is a CSS file in which allclass names and animation names are scoped locally by default.

Basically, the same class names do not clash when used in different CSS files. Say you have Button.css and Header.css, then in each of those files, you have a class named .bg-color like so

// Button.css
.bg-color{background:red;}

// Header.css
.bg-color{background:blue;}

When React runs, the classes will be actually named something like this .Button_bg-color__18rA{…} and .Header_bg-color__94tO{…}. They follow the following naming convention: [filename]\_[classname]\_\_[hash].

Continuing with the Sass example, open App.scss and add the following

.btn {
  width: 200px;
  height: 50px;
  font-size: 20px;
  border-radius: 5px;
  margin-top: 20px;
  background: rgb(199, 196, 23);
  border: none;
  &:hover {
    background: rgb(236, 233, 36);
  }
}

Now open App.js and the highlighted code

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

class App extends Component {
  render() {
    return (
      <div className="App">
        <header className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <p>
            Edit <code>src/App.js</code> and save to reload.
          </p>
          <a
            className="App-link"
            href="https://reactjs.org"
            target="_blank"
            rel="noopener noreferrer"
          >
            Learn React
          </a>
          <button 
            className="btn" 
            onClick={() => alert('I am globally styled')}>
              I am button 1 - Press Me
          </button>
          <Button />
        </header>
      </div>
    );
  }
}

export default App;

We are basically creating a button and assigning a .btn class to it. We also create a Button component.

Now, let’s actually create the Button component and the related stylesheet file under the ./src directory

touch Button.js Button.module.scss

Notice I am creating a CSS Module here

Open Button.module.scss and add the following

.btn {
  width: 200px;
  height: 50px;
  font-size: 20px;
  border-radius: 5px;
  margin-top: 20px;
  background: rgb(199, 23, 23);
  color: white;
  border: none;&:hover {
    background: rgb(228, 49, 49);
  }
}

To demonstrate, I am using the same class name (.btn) as in App.scss.

Now open Button.js and add the following

import React from 'react';
import { btn } from './Button.module.scss';

const Button = () => {
  return (
    <>
      <button
        className={btn}
        onClick={() => alert('I am styled with CSS Modules')}
      >
        I am button 2 - Press Me
      </button>
    </>
  );
};

export default Button;

Highlighted you will see how we can import the stylesheet to make use of CSS Modules.

You can use destructuring (as I am currently doing) or the dot notation like so

import styles from './Button.module.scss';
...
      <button
        className={styles.btn}
        onClick={() => alert('I am styled with CSS Modules')}
      >
        I am button 2 - Press Me
      </button>
...

It is time to run the app.

yarn start
CSS Modules
CSS Modules

Notice the two classes are not clashing. The one globally created in App.scss stayed as .btn and the one created with CSS Modules is now .Button_btn__18rA.

Finally, let’s build the app.

yarn build

Open the generated stylesheet under ./build/static/css/main.[hash].css and you will notice both classes are present, but they don’t clash as they are named differently.

Generated stylesheet
Generated stylesheet

Conclusion

I hope you enjoyed this article and thank you for reading. If you have any questions, suggestions or corrections let me know in the comments below. Don’t forget to give this article a share and you can follow me on Twitter or connect with me on LinkedIn!

Thanks for reading!


Originally posted on Bits and Pieces


Consider giving back by getting me a coffee (or a couple) by clicking the following button:

[bottomads][/bottomads]

Spread the love

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.