Styling React components with css modules and themes.

Our requirements

We have 3 different apps: web app, android and iOS. Each app has its own custom styles.
We’re using React, Webpack and css-modules.
Your components in the different apps share the same structure and logic, only theme settings are changing.

The Problem

How to use the same identifiers but create different styles for each app?

The current scenario force us to update our components to make them aware of themes by using some plugin. Sometimes this is what you want, because themes are a dynamic part of your system. But sometimes, you want to create different builds for different apps; think about creating different layouts for android or iOS, or creating different themes and do some AB testing with them.

This is where this loader comes handy, the idea is to create the themes in our css or sass file, and then the loader will take care of including the correct css rules

Install it

npm install cssthemes-loader --save-dev

Setup

Write your css modules with selectors like you want, I recommend using it with :<selector> and then adding the styles there for each theme.

.elem {
color: white;
font-size:10px;

.subelem {
color: green;
}
}

.elem2 {
font-size: 16px;
}

:android {
.elem {
color: blue;
text-align: center;
}
}

:ios {
.elem {
color: red;
}

.elem2 {
font-size: 12px;
}
}
Your React component will remain the same, no need to change anything there, which I think it’s the cool part of this.

You’ve to include the loader before (in webpack’s logic) sass-loader or css-loader. For this particular configuration we’re ignoring the :ios selector, and including the :android selector as the main one.

// webpack.config.js
{
...
module: {
rules: [
...
{
test: /\.s?css$/,
use: [
{
loader: 'style-loader'
},
{
loader: 'css-loader'
},
{
loader: 'sass-loader'
},
{
loader: 'cssthemes-loader',
options: {
target: ':android',
ignore: [':ios']
}
},
],
exclude: /node_modules/,
}
],
}
}

This example is for running with hot reloading so we’re using style-loader, but you can also use extract-text-webpack-plugin or any other, this loader just clean up the initial styling rules.

Now after running the webpack command we’ll get this css for this module

.elem {
color: blue;
font-size: 10px;
text-align: center;

.subelem {
color: green;
}
}

.elem2 {
font-size: 16px;
}

And that’s it!

Here you find the repository in case you want to check the code or change it, or whatever. Feel free to write comments if you’ve used the loader or if you think it’s a terrible, terrible idea.

Thanks for reading!