Evan Cordulack

CSS Modules and React Notes

July 29, 2020

Overview

Maintaining global CSS rules can be tricky. If you ever have to alter a CSS rule used by different HTML elements (or the React components that generate them), you have to make sure you don't accidentally change components that shouldn't change.

Build tools like Webpack allow you to use CSS Modules to locally scope your CSS and make it clear what components rely on what CSS. Once you have your build tools set up to use CSS Modules, it will process your class names to make them only apply to specific templates. Now you can easily update the CSS for a single component without worrying about changing components.

Using CSS Modules in an app created by Create React APP

If you want to use CSS Modules:

  1. Add .module.css to the end of your CSS file
  2. Import that CSS file into your JS file import styles from ./some-file-name.module.css
  3. Add the className prop to your component like this: className={styles.someclassname}

If you use a class name in a component, and define it in your .module.css file, CSS Modules will change the names of both so they are locally scoped.

Example

If you have this in your component:

<img className={styles.someclassname} src={teaserImage} />

and .someclassname is in your styles.module.css file, the final HTML in your app will elements with your new locally scoped class name like this

<img class="styles_someclassname__15W4Y" src="https://via.placeholder.com/150/9c9c9c/fff" />

Notice the pattern: <css file name>_<original class name>_<generated hash>

Naming Classes: Using Hyphens or Dashes in Your Class Names

The maintainers of CSS Modules recommend using camelCase for your class names. However, you still use hyphens if you want. Because hyphens aren't allowed in JavaScript names, we have to tweak things a bit of you want hyphens/dashes in your class names.

You can alter how you access the value for your className property:

<img className={styles['some-class-name']} src={teaserImage} />

or, you can update your WebPack configuration, so it will transform your camelCased variable names to class names with dashes. Check out the Webpack docs about the CSS Loader configuration for some more information.

Naming Classes: You Can Use Shorter Class Names

Because you no longer have to worry about naming collisions, or losing track of what class applies to what HTML Element, you can use more minimal class names.

For instance, if you have a css module file named list-article.module.css, your class names inside that file can be more like .title or .featuredImage instead of .listArticleTitle or .listArticleFeaturedImage

Multiple Classes On A Component

If you want to put multiple classes in the className prop, you will be using some JavaScript. There are several ways to do this, but they don't seem to be recommended.

Here is a way to do it with a template literal: className='{${styles.someClass} ${styles.someOtherClass}}'

Composing Classes

One of the ideas behind CSS Modules is that each module has everything it needs to render an element, and you can do this using a single class. The problem here is that you can't just list out all the properties an element needs without duplicating code between elements. Eventually, you will need to share code.

In order have a single class completely describing an element and share code when appropriate, we can create our classes using composes. Make sure the composes rule are at the beginning of your rule.

@import 'someFile.scss';

.myClass {
  composes: someClassFromTheFileWeImported;
  color: black;
  padding: 10px;
}

If you have more than one class to include via composes, you can have multiple composes or mutliple classes in a single composes

.myClass {
  composes: someClassFromTheFileWeImported;
  composes: differentClassFromTheFileWeImported;
  color: black;
  padding: 10px;
}
  composes: someClassFromTheFileWeImported differentClassFromTheFileWeImported;

See Glen Maddern's article for a good explanation for using composition and CSS Modules

Sources