React
  • Introduction
  • Getting Started
    • Introduction
    • Before you get started
  • 1. Fundamentals
    • Introduction
    • Rendering
      • JSX
      • Exercise
      • Solution
    • Components
      • Stateless
        • Exercise
        • Solution
      • Stateful
        • Exercise
        • Solution
      • Styling
        • Exercise
        • Solution
        • Using CSS Modules
    • Folder Architecture
  • 2. Intermediate
    • Lifecycle methods
    • Controlled and Uncontrolled components
    • Anti-patterns
    • Refs and the DOM
    • Lifting State Up
  • 3. Advanced Topics
    • Conventions
    • Reconciliation
    • Performance Optimizations
      • Avoiding Reconciliation
      • PureComponent
      • Avoiding inline lambdas
      • Development vs Production build
    • Context
  • 4. Advanced Patterns
    • Higher-order Components
    • Children as Function
    • Renderless Components
    • Portals
    • Error handling
  • Exercises
    • Introduction
    • 1. ProductList light
      • Step 1
      • Step 2
      • Step 3
      • Step 4
      • Extra
      • Solution
Powered by GitBook
On this page
  • References
  • CSS Modules
  • In practice
  • CSS conventions
  • classNames
  • Further Reading
  1. 1. Fundamentals
  2. Components
  3. Styling

Using CSS Modules

PreviousSolutionNextFolder Architecture

Last updated 6 years ago

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

css-loader Github repo

classnames Github repo

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 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

Glamorous

Glamor

Emotion

Styled-jsx

https://github.com/css-modules/css-modules
https://github.com/webpack-contrib/css-loader
https://github.com/JedWatson/classnames
css-loader
https://github.com/styled-components/styled-components
https://github.com/paypal/glamorous
https://github.com/threepointone/glamor
https://github.com/emotion-js/emotion
https://github.com/zeit/styled-jsx