Alejandro Napoles

Alejandro Napoles


Thoughts and ideas about programming, technology and my life as a lifelong learner and developer.

Share


Tags


Twitter


React and CSS Modules

Working with React has been an amazing experience so far. It has broadened my view (no pun intended) in certain ways. One of the first things I liked was not ev…

Alejandro NapolesAlejandro Napoles

Working with React has been an amazing experience so far. It has broadened my view (no pun intended) in certain ways. One of the first things I liked was not even a specific React only concept. I'm talking about components and how you can make standalone components that can be plugged easily into the UI and work with each other, basically using (if someone wants to strive for good code) design principles like separation of concern, composition, loose coupling, etc. I really like this approach and I'm very interested to see how the Web Components standard progresses in the future.

The component/modular approach stuck with me, and that's why when I had to add styles to React components it didn't feel right. I wasn't fond of styling them with global CSS, since I want the styles of a component to be associated to that specific component alone. Because of this, I started to investigate what other people was doing about this. I was already aware of inline styling and libraries like Radium, but it didn't click for me. Some styles, in my opinion, needs to be inline, since there are occasions where there is no other way; Some example that comes to mind is a component having to calculate its own width dynamically, but most of the time you can use regular CSS and class names to style it. I found what I was looking for all along, CSS Modules.

CSS Modules

A CSS Module is a CSS file in which all class names and animation names are scoped locally by default.

It's so simple as:

import styles from "./style.css";

const someComponent = () => <div className={styles.someClass}></div>;

With CSS Modules the styles are local, you can reuse them and compose them with other classes in the same CSS or even from other modules:

.box {
  width: 100px;
  height: 100px; 
  border: 1px solid #dddddd;;
}

.button {
  composes: box;
  background: #c1e000;
  border-radius: 30px;
}

.icon {
  composes: baseIcon from "./base.css";
}

This way you can apply the same modular concepts that you're using in React to the CSS, which I think is great and coherent.


As far as I know CSS Modules only works with Webpack (although I've seen this highly experimental browserify plugin: css-modulesify), specifically with css-loader or postccs-loader.

Basically, CSS Modules takes your CSS files and compiles them to ICSS (read more about it in this great post from Glen Maddern), and what you'll see in your classes are unique identifiers:

<main class="app__main___3ho4G">
 <div class="productTable__container___1tcKh">
  //...
 </div>
</main>

react-css-modules

If you think using the styles object every time (className={styles.someClass}) is cumbersome and you're a fan of destructuring the object:

import {someClass, otherClass} from "./styles.css";

const someComponent = () => <div className={someClass}></div>;

You may want to give react-css-modules a try. React-css-modules decorates your React component making the loading of CSS Modules automatic through a styleName property:

import React, {Component} from "react";
import CSSModules from "react-css-modules";
import styles from "./styles.css";

class someComponent extends Component {
	render() {
		return (
			<div styleName="container">
				{this.props.children}
			</div>
            <p styleName="someClass">Hello there!</p>
		)
	}
}

export default CSSModules(someComponent, styles);

Since I'm using styleName here I'm also free to apply global styles with className if I need to.

What happens now with external CSS libraries?

Maybe you just went to use CSS Modules right away after discovering its wonders, but now you want to use some external CSS like Font-Awesome or Bootstrap only to find that that icon you want to use so badly doesn't even appear in your page, although everything seems to work. I feel you, that happened to me. What I didn't realize at first, which is weird considering what it does, was that the following configuration:

{
  test: /\.css$/,
  loader: 'style!css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]' 
}

Was also including the node_module directory, ergo, that external css library installed with npm was also getting compiled to ICSS. After some research I found the following issues in the CSS Modules GitHub page:

Some of the options were: composition, @import or adapt the library to CSS Modules. I decided to go for the easiest option of all, just for this project I'm working on, which is making CSS Modules ignore node_modules and having another test for node_modules to load the external CSS as-is.

Comments