R

React Handbook

Clean • Professional

React CSS Modules

2 minute

CSS Modules in React

When building large-scale React applications, managing styles can become tricky. Global CSS files can cause class name conflicts and make it hard to maintain your app. This is where CSS Modules come in.

CSS Modules provide component-level scoped styles, meaning each CSS class is local to the component that imports it. This ensures clean, maintainable, and reusable styling.

Why Use CSS Modules?

  1. Scoped Styling – Avoids global class conflicts.
  2. Reusable Components – Each component can have its own styles.
  3. Maintainable CSS – Styles are easier to read and organize.
  4. Supports Standard CSS Features – Media queries, pseudo-classes, and animations still work.

How CSS Modules Work in React

  1. Create a CSS file with the .module.css extension.
  2. Import the styles into your React component.
  3. Use the imported styles object to apply class names.

Creating a CSS Module

Button.module.css

.button {
  background-color: #007bff;
  color: white;
  padding: 10px 20px;
  border-radius: 5px;
  cursor: pointer;
  border: none;
}

.button:hover {
  background-color: #0056b3;
}

Using CSS Modules in a React Component

Button.js

import React from "react";
import styles from "./Button.module.css";

function Button({ text }) {
  return <button className={styles.button}>{text}</button>;
}

export default Button;
  • styles is an object where each key corresponds to a CSS class.
  • The class names are scoped locally — React automatically generates unique class names under the hood.
  • Hover effects, media queries, and other CSS features work normally.

Passing Props for Conditional Styling

You can apply different styles based on props:

Button.module.css

.primary {
  background-color: #007bff;
  color: white;
}

.secondary {
  background-color: #6c757d;
  color: white;
}

.button {
  padding: 10px 20px;
  border-radius: 5px;
  border: none;
  cursor: pointer;
}

Button.js

import React from "react";
import styles from "./Button.module.css";

function Button({ text, type }) {
  const buttonClass =
    type === "primary" ? styles.primary : styles.secondary;

  return <button className={`${styles.button} ${buttonClass}`}>{text}</button>;
}

export default Button;
  • The buttonClass dynamically applies styles based on the type prop.
  • Combining class names with template literals ensures flexible styling.

Using Nested Components with CSS Modules

Card.module.css

.card {
  border: 1px solid #ddd;
  padding: 20px;
  border-radius: 10px;
  background-color: #f9f9f9;
}

.cardTitle {
  font-size: 20px;
  font-weight: bold;
  margin-bottom: 10px;
}

Card.js

import React from "react";
import styles from "./Card.module.css";

function Card({ title, children }) {
  return (
    <div className={styles.card}>
      <h3 className={styles.cardTitle}>{title}</h3>
      <div>{children}</div>
    </div>
  );
}

export default Card;

Advantages of CSS Modules

FeatureBenefit
Scoped CSSNo global conflicts, styles are local to components
ReusableEach component can have its own styles
Dynamic StylingWorks with props for conditional styling
Familiar CSS SyntaxYou can use media queries, pseudo-classes, transitions
MaintainableEasier to read, especially in large apps

Example of Combined Features

This will render two buttons with independent, scoped styles, avoiding conflicts with other components.

import React from "react";
import styles from "./Button.module.css";

function App() {
  return (
    <div>
      <Button text="Primary Button" type="primary" />
      <Button text="Secondary Button" type="secondary" />
    </div>
  );
}

export default App;

 

Article 0 of 0