Have you ever been styling a component, only to realize that unwanted CSS rules are being applied?

Maybe you then go refactor another section of the CSS so the rules don't apply, or maybe you throw up your hands and add some !important rules just to get it working?

This is the problem that CSS Modules solve. Let's look at the official definition of a CSS Module:

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

The key words here are scoped locally. With CSS Modules, your CSS class names become similar to local variables in JavaScript.

By the way, a 'CSS Module' is just a .css file. You call it a 'CSS Module' if you plan on using it with a CSS Modules compiler.

Let's visualize what we have so far:

A CSS Module goes into the compiler, and CSS comes out the other side.

Where do you get a CSS Modules compiler? If you are using Webpack, you already have one. Just add the ?modules option to css-loader. For an example, see: github.com/css-modules/webpack-demo.

If that's too abstract for you, let's take a concrete example:

Notice how the meow class is renamed to cat_meow_j3xk. Let's break that down:

  • cat: the file name
  • meow: the local class name
  • j3xk: a random hash

These combine to create cat_meow_j3xk which is unique globally. This is important because your browser doesn't have a concept of 'local scope' for CSS. If CSS rules are not unique globally, then they will overlap.

So far so good, but how do you get that globally unique name? Are you going to type className="cat_meow_j3xk" in all your React components? Of course not.

CSS Modules actually has another output that I previously hid from you. A JavaScript object with all of your renamed classes:

Here's the updated concrete example:

Notice that the JavaScript object has meow as a key, and that matches the class name that you chose in your CSS Module. object.meow will give you the renamed class.

To use a CSS Module with React you would add the CSS to your web page and import the JavaScript object into your component. Let's add that to the diagram:

To make it even more concrete, let's tie it all together with a sample React component. Here Cat.js is a React component and Cat.css is the accompanying CSS Module:

Cat.css
.meow {
  color: orange;
}
Generated CSS
.Cat_meow_j3xk {
  color: orange;
}
Cat.js
import React from 'react';
import styles from './Cat.css';
 
class Cat extends React.Component {
  render() {
    return (
      <div className={styles.meow}>
        Orange Cat
      </div>
    );
  }
}
export default Cat;
Generated JavaScript
{
  meow: 'Cat_meow_j3xk'
}
Demo
Orange Cat

Calling import styles from './Cat.css' imports the Generated JavaScript. styles.meow will equal "Cat_meow_j3xk".

The React component sets the styles.meow on a div, and you can see that the text turns out orange in the demo.

Conclusion

Quite a bit of work for orange text, I know! But on big projects, it pays off. The real joy of working with CSS Modules is this:

Whenever I start a new component, I know that there are no global styles that will interfere with my work.

Still confused? Maybe you learn better with examples? Check out CSS Modules by example. I run you through a list of the most common scenarios you'll encounter with CSS Modules, and I show you exactly how the CSS Modules compiler will behave in each instance.

By the way, it took days for me to figure out what CSS Modules are and how they work. Don't waste time like I did - sign up for my newsletter and I'll help you learn the newest technologies quickly ( i.e. with pictures 😉 ).