Component scoped css modules in React Js

Last updated : 23 July 2022

Component-scoped CSS is proper to avoid CSS class name clashes. React Js allows you to use CSS modules to work around this problem. You can use CSS modules in your React Js application if your react-scripts version is 2.0 or higher.

What do CSS modules solve?

The issue we face using CSS is the class name conflicts. When you import the CSS file, the CSS classes defined in the CSS file become global. In other words, any CSS files imported into your component are visible throughout the application.

In the below example, I imported the Styles.css file in the SuccessMessage component. I intended to limit classes in the Styles.css only to the SuccessMessage scope. But they are applied to all the elements in the application. That's not what I wanted.

Styles.css

.buttonClass {
  background-color: green;
  color: white
}
.spanClass {
  color: rgb(11, 222, 85);
}
.divClass {
  margin: 24px;
}

App.tsx

import SuccessMessage from "./components/SuccessMessage"
import ErrorMessage from "./components/ErrorMessage"
import { useState } from "react"
export const App = () => {
  const [message, setMessage] = useState("success")
  const toggleMessages = () => {
     setMessage((prev) => {
     return prev === "success" ? "error" : "success"
  })
}
return(
  <>
  {message === "success" && <SuccessMessage/>}
  {message === "error" && <ErrorMessage/>}
  <div className="divClass"><button onClick={toggleMessages}>Show {message === "error" ? "Success" : "Error"} message</button></div>
  </>
)
}
export default App

SuccessMessage component imports Styles.css

Importing Styles.css to use locally. But the styles become global to the application.

import "../Styles.css"
const SuccessMessage = () =>{
  return(
          <div className="divClass">
            <span className="spanClass">Your Account has been created successfully</span>
            <br/>
            <button className="buttonClass">Go to account</button>
          </div>
  )
}
export default SuccessMessage

ErrorMessage component

The ErrorMessage component is also affected by the SuccessMessage style imports. Note that the CSS classes for the button, span, and div also apply to this component's elements. But what if I want different styles in this component?

const ErrorMessage = () =>{
  return(
          <div className="divClass">
           <span className="spanClass">We could not create your account</span>
           <br/>
          <button className="buttonClass">Contact customer service</button>
          </div>
  )
}
export default ErrorMessage
React Js css modules global css
Figure 1: React Js css modules global css

How to use CSS modules to limit the CSS scope

If your app uses react-scripts version 2.0 or higher, you are all set to use CSS modules. The only change to consider is the naming convention of the CSS modules. It usually follows the [component].module.css pattern. However, the module.css is not optional. In the below example, I have created two different CSS modules for SuccessMessage and ErrorMessage components. Then I import each module as styles. This way, the class names from Styles.css are overridden by the class names from CSS modules. The components get the class names divClass, buttonClass, and spanClass from their own CSS module with a unique class name.

SuccessMessage.module.css

.buttonClass {
  background-color: green;
  color: white
}
.spanClass {
  color: rgb(11, 222, 85);
}
.divClass {
  margin: 24px;
}

SuccessMessage component with CSS modules

import styles from "./SuccessMessage.module.css"
import "../Styles.css" //we have duplicate class names here
const SuccessMessage = () =>{
  return(
          <div className={styles.divClass}>
            <span className={styles.spanClass}>Your Account has been created successfully</span>
            <br/>
            <button className={styles.buttonClass}>Go to account</button>
          </div>
  )
}
export default SuccessMessage

ErrorMessage.module.css

.buttonClass {
  background-color: red;
  color: white
}
.spanClass {
  color: red;
}
.divClass {
  margin: 24px;
}

ErrorMessage component with CSS modules

import styles from "./ErrorMessage.module.css"
const ErrorMessage = () =>{
  return(
          <div className={styles.divClass}>
           <span className={styles.spanClass}>We could not create your account</span>
           <br/>
          <button className={styles.buttonClass}>Contact customer service</button>
          </div>
  )
}
export default ErrorMessage
React Js css modules local scope
Figure 2: React Js css modules local scope

CSS modules' dynamic class names

The usage of CSS classes is a little different. I use className={styles.buttonClass} etc instead of className="buttonClass". This way, React Js generates a dynamic class name for each class name usage. For example, the CSS class .divClass will have different class names in each usage.

React Js css modules dynamic class names
Figure 3: React Js css modules dynamic class names

CSS modules enable CSS classes to scope to the component level. It allows us to solve CSS class name clashes by generating dynamic and unique class names.

Lance
By: Lance
Lance is a software engineer with over 15 years of experience in full-stack software development.
Read more...

Leave a comment

No Comments