CSS Modules in React.js

CSS Modules in React offer a way to locally scope your CSS by automatically creating unique class names. This eliminates the risk of class name collisions and makes styles more modular. CSS Modules are a great way to maintain consistent styles in larger applications, where global styles might become hard to manage.


1. What Are CSS Modules?

CSS Modules allow you to write standard CSS, but the class names are scoped locally to the component by default. This means that the styles you define in a CSS module won’t affect other parts of the application unless explicitly imported. React processes CSS Modules during the build phase, transforming class names into unique strings.


2. Setting Up CSS Modules in React

To use CSS Modules in a React project, ensure that your file names follow the .module.css convention. This tells React that the file is a CSS Module.

Example:

Button.module.css:

				
					.button {
  background-color: blue;
  color: white;
  padding: 10px 20px;
  border: none;
  border-radius: 5px;
}

.button:hover {
  background-color: darkblue;
}

				
			

Button.js:

				
					import styles from './Button.module.css';  // Import the CSS module

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

export default Button;

				
			
Here’s what happens:
  • The CSS module (Button.module.css) defines styles for the .button class.
  • In Button.js, the styles object is imported. The styles.button key corresponds to the .button class.
  • React generates a unique class name for .button (e.g., Button_button__1AbCd) to ensure the style is scoped only to this component.

  • 3. Dynamic Class Names with CSS Modules

    CSS Modules allow you to dynamically apply class names using JavaScript logic, which can be helpful when applying conditional styles.

    Example:

    				
    					import styles from './Button.module.css';
    
    function Button({ primary }) {
      return (
        <button
          className={primary ? styles.buttonPrimary : styles.buttonSecondary}
        >
          Click Me
        </button>
      );
    }
    
    export default Button;
    
    				
    			

    Button.module.css:

    				
    					.buttonPrimary {
      background-color: blue;
      color: white;
    }
    
    .buttonSecondary {
      background-color: gray;
      color: white;
    }
    
    				
    			

    In this example, the button’s class name is determined based on the primary prop. If primary is true, the buttonPrimary class is applied; otherwise, buttonSecondary is used. This allows for dynamic styling using CSS Modules.


    4. Composing Multiple Class Names

    Sometimes you may need to apply multiple class names to a single element. You can combine multiple classes in CSS Modules using template literals or libraries like classnames.

    Example of Combining Classes:

    				
    					import styles from './Button.module.css';
    
    function Button() {
      return (
        <button className={`${styles.button} ${styles.large}`}>
          Click Me
        </button>
      );
    }
    
    				
    			

    Button.module.css:

    				
    					.button {
      background-color: blue;
      color: white;
    }
    
    .large {
      padding: 20px 40px;
    }
    
    				
    			

    Here, both the button and large classes are applied to the button element. The resulting class might look something like Button_button__1AbCd Button_large__2XyZz.


    5. Using the classnames Library

    For more complex scenarios where you need to combine multiple classes conditionally, you can use the classnames library. This library simplifies managing dynamic class names.

    Installation:

    				
    					npm install classnames
    
    				
    			

    Example with classnames:

    				
    					import styles from './Button.module.css';
    import classNames from 'classnames';
    
    function Button({ large, primary }) {
      const buttonClass = classNames({
        [styles.button]: true,
        [styles.large]: large,
        [styles.primary]: primary
      });
    
      return <button className={buttonClass}>Click Me</button>;
    }
    
    export default Button;
    
    				
    			

    In this example, the classnames library conditionally applies the large and primary styles based on their respective values, making the syntax cleaner.


    6. Scoped Animations and Transitions

    CSS Modules can also be used for defining animations and transitions, ensuring they don’t accidentally affect elements outside the component.

    Example:

    Button.module.css:

    				
    					@keyframes fadeIn {
      from {
        opacity: 0;
      }
      to {
        opacity: 1;
      }
    }
    
    .button {
      background-color: blue;
      color: white;
      padding: 10px 20px;
      border-radius: 5px;
      animation: fadeIn 2s ease-in-out;
    }
    
    				
    			

    Button.js:

    				
    					import styles from './Button.module.css';
    
    function Button() {
      return <button className={styles.button}>Click Me</button>;
    }
    
    export default Button;
    
    				
    			

    The fadeIn animation is scoped only to the button component, ensuring that it does not affect other elements on the page. This modularity allows for cleaner and more maintainable animations.


    7. Benefits of CSS Modules

  • Locally Scoped: CSS Modules prevent styles from leaking out or affecting other parts of the application. This is especially helpful in large applications where global styles can cause conflicts.
  • Automatic Unique Class Names: React ensures that class names are unique, avoiding naming conflicts between different components.
  • Easy to Maintain: CSS Modules are easy to manage, as each component has its own scoped styles.
  • Reusable: Styles can be reused across components without fear of conflicts or the need to use complex naming conventions (like BEM)

  • 8. Limitations of CSS Modules

  • Global Styles Still Required: CSS Modules are great for component-level styling but not suited for managing global styles like typography, layout grids, or resets.
  • Complexity in Dynamic Styles: While dynamic styling is possible with CSS Modules, it can become cumbersome in scenarios that require a lot of conditional logic. Solutions like styled-components or Emotion may offer a more flexible approach in such cases

  • Conclusion

    CSS Modules in React provide a powerful and scalable way to manage styles in your applications. They offer a modular approach, ensuring that styles are scoped to specific components and don’t leak across the application. By using locally scoped class names, CSS Modules help reduce the risk of conflicts and make it easier to maintain styles, especially in larger applications.

    ×