React and JSS: tips from a one-year journey

More than one year ago we started a new project: a universal SPA based on React and Redux. One of the first choices to make was: “how do we handle stylesheets?”. We gave a chance to JSS. 60+ components later, it has been the best experience we had with stylesheets so far. Here are some technical solutions we adopted and the overall feedback.

I was initially skeptic about the CSS-in-JS solutions that were recently gaining popularity. Probably I was overestimating the benefits of working with a toolset that I already knew, SASS, compared to the many benefits JSS brings to a React project. Anyway, after some internal team discussions, we decided to give JSS and its React integration (react-jss) a chance.

At the beginning not everything was straightforward: here is how we managed to solve some of the problems we discovered.

Global styles might still be useful

JSS encourages you to use component-scoped styles. This means that you define a stylesheet for a single component, then at runtime react-jss generates the unique class names that will be used by the same component when it’s rendered. If a component is not rendered, the styles of that component are omitted from the page.

This solution fits naturally in a component based application, and since the class names generated by react-jss are scoped you never have to deal with rules overriding, which in the long term is in my opinion the biggest source of maintenance headaches (yes, in some ways it encourages you to avoid the “cascading” part of CSS on purpose).

There are some exceptions though, we really wanted the reset.css stylesheet and the fonts definitions to be globally defined in the application. JSS provides for this reason a jss-global plugin that, when enabled, do not add the namespace on class names for styles defined within the special @globaldefinition:

// "image" won’t be namespaced
const styles = {
'@global`: {
image: { backgroundColor: 'red' },
},
};

With non-namespaced rules, we also needed to find a way to always display the CSS rules independently from the active components, and also display them before components-related CSS rules.

One solution consists into adding this set of rules to the Root component of the application. Since react-jss renders one script tag for every component in the head of the HTML page starting from the Root component towards the inner components, we have the guarantee that these styles are rendered before any other style (perfect for reset.css and fonts). At the same time the Root component is always present in the application, which satisfy our first need.

There’s another more complicated way to add a some global styles without attaching it to a single component. I used this method to render global styles in a Storybook, where I don’t have access to the Root component (which is rendered by Storybook itself). I really didn’t want to wrap any single component with an additional Root component just to add some global styles, so I ended up with the solution you can see in this CodeSandbox.

https://codesandbox.io/s/y33wnkvk71

What about external components?

Sometimes it’s convenient to include in our project open source components made by other developers. Since there seems to be no clear winner between the stylesheets management solutions for React, developers packaged styles in different ways: some of them provides inline styles, other provides a CSS file to be manually included in your project.

We didn’t want to handle externally provided styles in a different way than we do with JSS, so we just converted the provided CSS to JSS through the JSS cli. Wrapping with @global the JSS rules in output before including them ensures these are not being namespaced during rendering, so the external component is able to reference them.

There’s one drawback though, manually converting the styles of the external component means we actually forked them. In case we update the npm package we have to regenerate it’s styles again. You might want to consider alternative solutions for this issue in your project.

Variables? Utility functions?

Since styles are just Javascript objects, we were able to define a set of Javascript variables that we then referenced in several components styles (like you could do with SASS variables). A later change of this values updates all the components styles, which is very useful when you want to define a primaryColor for example.

Theming, intended as the ability to switch between sets of variables changing the appearance of the application, becomes then pretty simple. To switch the active variable set, you can set a config via .env, or you can set it through the webpack DefinePlugin (be aware that using this solution you’re actually setting the variables at compile time).

Since everything is Javascript code then, we were able to trivially create some utility functions that we could use in our styles definitions. For example our pxToRem function, that we use almost everywhere we need to define the size of something, and the shadeColor function, which takes a color and returns a lighter or darker version of it. 
We didn’t have to resort on another language, it’s just testable Javascript.

What about server side rendering?

The react-jss documentation provides some lines and a small example related to Server Side Rendering. It’s simple, but there’s one thing you need to notice:

After the application is mounted, you should remove the style tag used critical CSS rendered server-side.

It looks unclear at first, but the JSS documentation does a better job explaining what you need to do, with an example:

Once JS on the client is loaded, components initialized and your JSS styles are regenerated, it’s a good time to remove server-side generated style tag in order to avoid side-effects, example in react.

In summary, you need to use the callback that you can pass as third argument ofReactDOM.render to clean up the server rendered styles. This is called when the app is loaded.

Conclusion

Now that we are one year into the project, I can say we really appreciated the benefits of using JSS. Any change request has a direct target in the form of a component, unwanted styles overrides are a bad reminder, and debugging has become less time expensive. The developer experience is overall really great, and our users benefits from a smaller CSS payload and zero unused CSS rules on the pages they view.

Over the last year the JSS project evolved, but the API has always been really stable, the only breaking change that involved our project was explicitly reported in the changelog, and it was related to the renaming of a component.

I would like to personally say thanks to Oleg Slobodskoi and all the people who contributed to JSS and its plugins for the amazing work they did.

If you like this post, subscribe to this publication on Medium to get all the updates and stay tuned. You can also click “Follow” below, next to my account to receive email updates from Medium.
And don’t forget to say “hello” on Twitter, my account is @darioghilardi!