A complete guide to CSS Modules in React (Part-1)

Any CSS that you import in a react application (or any frontend
application in general) by using below syntax is loaded into global scope:
import './app.css';
The issue with this approach is that by importing CSS in global scope, we
pollute the global scope and it can result in conflicts.
Suppose 2 developers are developing 2 different modules in a project Module A and Module B. Both modules have a submit button and 2 developers apply the same class ‘submitButton’ not realizing that the same class name was used by other developers as well. Look at the below piece of code as an example:
filename : module1.css
.submitButton {
color :red ;
}
filename : module2.css
.submitButton {
background-color :blue;
}
filename : module1.js
import React , { Component } from ‘react’
import ‘./module1.css’export default class Module1 extends Component {
render () {
return (
<div>
<button className = “submitButton”>
Module 1
</button>
</div>
)
}
}
filename : module2.js
import React , { Component } from ‘react’
import ‘./module2.css’export default class Module1 extends Component {
render () {
return (
<div>
<button className = “submitButton”>
Module 2
</button>
</div>
)
}
}
When the final application is rendered, the 2 CSS classes above will conflict and produce an undesired output and shown below:
Let’s look at the CSS applied:
One approach to avoid this is that each developer, before choosing a class name, looks at the entire project and chooses a class name accordingly.
But, what if you import an external CSS(while including a 3rd party library) in index.html of your application and somehow that CSS conflicts with the CSS you wrote? What if everything was running great and one day you decided to import a 3rd party library and everything broke due to CSS conflict. Polluting the global space with CSS specific to a module or component brings with it a lot of overheads in terms of maintenance. A lot of the above issues can be avoided with the use of modular CSS.
Introduction to modular CSS
As the name suggests, Modular CSS is a CSS specific to a module and helps in avoiding conflicts as the CSS classes apply to only a specific nodule on which we intend to apply.
This is achieved with below syntax:
import styles from ‘./module1.module.css’<button classname = {styles.submitButton}> </button>
Let's revisit our last example and apply modular CSS.
Rename the CSS files to include the naming convention .module.css instead of .css (This is only in case you are using create-react-app as create-react-app supports CSS modules out of the box. The only catch here is that the CSS module should be named filename.module.css. Any CSS without .module.css extension can only be imported normally.) Modify the Module1 and Module2 as below:
filename : module1.js
import React, { Component } from 'react'import styles from './module1.module.css'export default class Module1 extends Component { render() { return ( <div>
<button className= {styles.submitButton}>Module 1</button>
</div> ) }}
filename : module2.js
import React, { Component } from 'react'import styles from './module2.module.css'export default class Module2 extends Component { render() { return ( <div>
<button className= {styles.submitButton}>Module 2</button>
</div> ) }}
The final output, as intended:
Now the question arises how does this work?
The answer is simple, with modular CSS, the class that we apply is not rendered on a browser with the same name, rather the class name changes or class name is modified into a unique value before applying.
Create react app compiles the class name in the below format:
cssFilename_classname_uniqueHash
Note that the class module1_submitButton__1119d is still accessible from anywhere in the application and is not “Private” to a module. But it no longer conflicts with any other CSS due to unique hashes.
In case you are not using create-react-app, you can apply the below to your webpack configuration to support CSS modules.
rules: [ { test: /\.css$/, use: [ { loader: 'style-loader', }, { loader: 'css-loader', options: { sourceMap: true, modules: true, localIdentName: '[name]_[local]_[hash:base64:5]' } } ], }
]
You can decide what will be the name of the CSS class when it renders on the browser with this webpack configuration.
Note the localIdentName field in webpack config decides what will be the class name when it finally renders. This can be configured.
Conclusion
I hope you liked the article. Do let me know in the comments section and be sure to checkout the 2nd part of this series here for a deeper dive into CSS modules and to learn how to use CSS modules in actual projects.