However, here I am, having used exclusively CSS-in-JS in enterprise design system environments for the last 2+ years. I think it’s a pretty solid choice. Why?
What Is The Problem CSS-in-JS Is Trying to Solve?
Developer complaints about CSS can mostly be combined into one programmatic issue: Everything in CSS is “globally scoped.” This means that all CSS rules are equally accessible by all of the code. CSS relies on the “cascade” part of “cascading style sheets” to determine priority order of rules. If you’ve ever worked through a CSS issue that has to do with “specificity,” “hierarchy,” or “the cascade,” that probably means you had an issue with global scope.
At Sparkbox and in the wider frontend web community, the way we eliminate these types of global scope-related bugs is by sticking to a sincere strategy for organizing our CSS. For example, ITCSS and BEM create pseudo-scopes of layout objects, blocks/components, elements, settings, tools, etc. A BEM (
.block__element--modifier) CSS rule is limited to the html element with the
What Benefits Does CSS-in-JS Bring to the Table?
outline: 2px dotted plum;
Some Button Text </button>
Could compile to something like this in the DOM, no inline styles to be found:
<button class=”js-generated-CSS-class”>Some Button Text</button>
Scoping your styles specifically to the component level is how CSS-in-JS solves the hierarchy issue. This is why many React (and similar) developers love using it in their codebases; all the styles live in your React component directory directly.
One of our most popular Sparkbox Foundry articles of all time is still a 2014 article by Ethan Muller, Naming CSS Stuff Is Really Hard. CSS-in-JS makes it so you don’t have to name things so carefully. You can still use names if you want, but because of the component-level scope, you can name things willy-nilly without fear of style collisions. It’s possible to use names like “button” or “heading” in multiple files and nothing will break on the page.
What Problems Does CSS-in-JS Create or Ignore?
As with all tools, you have to do the thing that is best for your project and team. If using CSS-in-JS makes your brilliant SCSS developer write mediocre CSS-in-JS, you are losing out on brilliant SCSS! However, there are certain CSS-in-JS libraries where the syntax can feel a lot like writing CSS (and even SCSS!). So your team should be able to go back to their awesome selves after an initial period of learning.
Another complication about CSS-in-JS is that converting existing code is likely no small effort. Imagine rewriting and duplicating your entire CSS codebase on a per-component basis. If that sounds terrible, maybe it’s not worth it. Only your team can decide “if the juice is worth the squeeze.”
.js files is probably over-engineering.
What Library Should I Use?
Using a style object has some drawbacks. CSS syntax is not always supported, so rules like media and feature queries might look very different. You’ll also have to rename all CSS properties to be camelCase (for example,
fontColor), and the correct translation is not always readily apparent.
CSS string templates are exactly what they sound like: a string template is compiled directly to CSS. Some Sass features are baked in with Emotion and other libraries, like the
& selector and the ability to nest components and media queries. Choosing a string template-based library is not only easier for your CSS developers to acclimate to, but it can also be a huge benefit if you choose to transition existing CSS. Just copy and paste.
Once again, Emotion—my old fav here—does allow you the option of either, but it’s not the only library out there. Styled-Components have so many of the same features that I’d call them interchangeable. If bundle size matters, Emotion v10 runs at about 6kb (though Emotion v11 is a cool 216b). Styled-Components adds about 15kb. There’s also CSS Modules (~10kb), JSS (6kb) or React-JSS (20kb), React-with-Styles (8kb), and countless other options.
To get to know the nuance of each library, I’ve found a tool called CSS-in-JS Playground helpful.
Okay, But What About Design Systems?
Most of my personal developer experience comes from implementing large-scale design systems for enterprise organizations. Many of those design systems have been created to support React component libraries, often built in Storybook and delivered to subscribers via npm modules. And this is the top scenario where this SCSS-fangirl supports using CSS-in-JS over SCSS. If you’re thinking about starting a new React-based design system or upgrading a current design system to better support React, CSS-in-JS can be a solid choice.
If your design system looks something like Bootstrap, that is if elements are styled by adding a number utility or token classes, many CSS-in-JS frameworks still support styling with class names. It’s possible to keep your class name-based system in place and convert to CSS-in-JS one component at a time. Additionally, the ephemeral nature of CSS-in-JS means that generated class names may change between builds, so you may wish to utilize a consistent class name system for accessibility anyway.
node_modules directly into a base SCSS stylesheet. It’s not a bad solution, but it does open a codebase up to collisions and scope leaks.
import, all the styles the component needs come with it as well.