Using CSS Modules With Create-React-App Without Ejecting
Leveraging CSS modules to avoid className collision
“How do you organize your CSS in a large project?”
This is a question that I always ask when I interview junior front-end developers. You would be surprised how many developers don’t have an answer to this question.
As our applications grow, the risk of className collisions increases as well.
Let’s take a look at a concrete example.
Here, we used the className
container in two different CSS files. Now the elements to which we give the
container className will have these styles mixed together, which is not what we want.
In this small example, it looks trivial and easy to avoid. But it’s not so easy to avoid when you are working on a large project with multiple team mates.
How should we organize our CSS in large project?
In the past, developers dealt with the global nature of CSS by relying on naming conventions. BEM (Block Element Modifier) was the most popular solution.
However, all of these solutions had the same limitation: they rely on the diligence of developers to avoid naming collisions.
What if, instead of relying on developers using unique classNames, we could instead rely on a tool that generates classNames for us at build time? Luckily for us, that tool already exists, and it’s called CSS Modules.
A CSS Module is a CSS file in which all class names and animation names are scoped locally by default
Using CSS Modules with
Luckily for us, CSS Modules are supported with
create-react-app out of the box. All we have do is properly name our CSS files. If we import a file with the extension
create-react-app will automatically treat it like a CSS module.
npx create-react-app css-modules-app
Open up the project in your favorite editor. Rename the file
App.module.css. Next, rename the import from
import './App.css' to
import styles from './App.modules.css. Finally, anywhere that you use a className, be sure to access the
styles object instead of the string className directly.
So instead of writing
className="App" you would write
Next, run your app and inspect the output. You will notice that CSS Modules has generated classNames for us.
App-header is now
App_App-header__xLkWl. The prefix is the name of the file
App.module.css. Then, it adds an underscore and our original className:
App-header. Finally, it adds the generated hash
xLkWl. This helps to ensure that our className will remain unique.
Writing global styles
Sometimes you need to write global styles. This is especially important when you need to override styles from external components. Doing this with CSS Modules is dead easy. Just use the
:global selector to switch from local to global scope.
Composing conditional styles
CSS modules works great with conditional styles. We often have to create components that have different appearances based on their props. Let’s take, for example, a simple
To make our lives easier, install the dependency
yarn add classnames
Next, we create two new files
The code is below:
TextInput is passed the properties
hasError, it adds the appropriate classNames.
Using CSS modules allows us to write locally scoped styles. This helps us to prevent naming collisions between our classNames. Since support for CSS Modules is baked into
create-react-app, we don’t even need to eject to take advantage of CSS modules.