Using CSS Modules

Let's see how we do style things at Shopify with CSS Modules and classnames. There are many other way of doing it, but that's what we chose to go with.

References

CSS Modules docs https://github.com/css-modules/css-modules

css-loader Github repo https://github.com/webpack-contrib/css-loader

classnames Github repo https://github.com/JedWatson/classnames

CSS Modules

The main concept behind CSS modules is fairly simple: scoped CSS. If you worked with CSS in the past you know that it is really easy to have name collision. That resolves in using certain conventions like BEM to try to prevent name collision but it is still not bullet proof.

When using CSS Modules with React, all the CSS you write will be scoped to your component. In reality, what happens is that all the class names you use are hashed to make them unique at compilation time.

Everything happens at compilation or load time thanks to webpack and the css-loader plugin. I won't go into webpack details here, but css-loader is just a CSS loader that is going to apply the principles of CSS Modules.

In practice

What happens in practice, is that instead of using your classNames as strings, you use a JavaScript object. Let's see a simple example to illustrate how it works:

import * as styles from './MyAwesomeComponent.scss'; 

export default class MyAwesomeComponent extend React.Component {
  render() {
    return (
      <div className={styles.MyAwesomeComponent}>
        ...
      </div>
    );
  }
}
.MyAwesomeComponent {
  background: pink;
}

Note that the file we import is an SCSS file, so you still get all the power of SCSS!

It is as simple as that. And depending on the configuration of css-loader the HTML output of this component will be something like:

._3P7e3N1Ustu5vbE4UZqtHO {
  background: pink;
}
<div class="_3P7e3N1Ustu5vbE4UZqtHO">
</div>

You can also configure css-loader to just have prefixes or suffixes to your existing classnames.

CSS conventions

Because all the CSS is now scoped, we don't need to use BEM anymore. Therefore the following style of writing:

.MyComponent {
  content: 'We use CamelCase for components.';
}

.HeaderOfMyComponent{ 
  content: 'If your component has an element inside, we also use CamelCase.';
}

.disabled {
  content: 'If you want to add a modifier class, you don`t need to prefix with your component name anymore.';
}

classNames

Now one question remains: how do you add multiple class names? Will I have to do things like:

<div className={`${styles.MyComponent} ${this.state.disabled ? styles.disabled : ''}`}>
</div>

Let's be honest, this is not really readable. And that's when the classNames utility comes in play. It's a simple utility for conditionally joining classNames together.

Let's see a real world example:

// If you use sewing kit:
import {classNames} from '@shopify/react-utilities/styles';
// or if you use directly the classnames package:
// import classNames from 'classnames';
import * as styles from './MyAwesomeComponent.scss'; 

export default class MyAwesomeComponent extend React.Component {
  render() {
    const {disabled} = this.state;
    const className = classNames(
      styles.MyAwesomeComponent,
      disabled && styles.disabled,
    );

    return (
      <div className={className}>
        ...
      </div>
    );
  }
}

Isn't this prettier?

There are plenty other way of styling in React, here are some well known and used libraries:

Further Reading

Styled Components https://github.com/styled-components/styled-components

Glamorous https://github.com/paypal/glamorous

Glamor https://github.com/threepointone/glamor

Emotion https://github.com/emotion-js/emotion

Styled-jsx https://github.com/zeit/styled-jsx

Last updated