1. Answers

Should I use CSS-in-JS?

There are a lot of CSS-in-JS libraries appearing, with styled-components being the most popular. These libraries allow you to write CSS within JavaScript files, without resorting to inline style.

What are the upsides and downsides of these libraries? Is it worth making the switch from separate CSS files?

James K Nelson

James is the editor of React Armory, and has been creating things with JavaScript for over 15 years.

Read more by JamesFollow @james_k_nelson on Twitter

The short answer: probably not, unless you can’t use standard CSS. Of course, the short answer is kinda boring. So let’s talk details.

Why (not) use CSS-in-JS?

A lot of big names in the React world are talking about CSS-in-JS. And honestly, it is easy to understand why. Good-ol’ CSS has its fair share of problems, so you’d expect that a lot of smart people would be looking for solutions.

But even if people are making progress towards a better way, I’m not convinced we’re there yet.

Which isn’t to say that CSS-in-JS doesn’t have its good parts. It does. But it also has some downright ugly parts, while more mature tools solve the same problems without the same downsides.

Existing tools work.

Most of the problems that CSS-in-JS solves can easily be fixed with more mature tooling like CSS Modules and Webpack. And if you’re considering using CSS-in-JS, these fixes are effectively free, because you’ll need Webpack anyway to put your CSS back into actual CSS files.

So here is my handy-dandy list of problems that you could have solved without using CSS-in-JS.

Eliminating globals

Let’s get this one out of the way first, because it is always the first thing that comes up in any list of reasons not to use CSS.

Yes, everything in CSS is a global:

.active {
    background: red;
}

/* ... lines and lines of unrelated code ... */

.active {
    /* oops */
    background: blue;
}

Luckily, there is an outstanding and mature solution to eliminating globals available: CSS modules. This comes bundled with Webpack’s CSS loader, so you can already use it, without doing anything.

But if you don’t want to use Webpack, there is an even simpler solution: use namespaces. And you don’t even need to use complicated namespacing techniques like BEM. Personally, I namespace classes based on the filesystem path and the name of the component they’re used in:

/* An `active` style for a `NavItem` component in the `app` directory */
.app-NavItem-active {
    background: red;
}

/* ... lines and lines of unrelated code ... */

.app-ContactForm-active {
    background: blue;
}

While this may look long-winded, if you’re using SCSS or LESS then the context selector with a dash &- makes things much simper:

.app-ContactForm {
  &-active {
    background: blue;
  }

  &-saving, &-fetching {
    /* style goes here */
  }
}

Of course, writing these long class names out in your JSX files can be a little painful. But there are tools to generate namespaced class names for you.

But then again, sometimes you want global styles, like this:

@import url('http://fonts.googleapis.com/css?family=Roboto:300,400');

Or this:

html, body {
  position: relative;
  height: 100%;
  min-height: 100%;
  font-family: Roboto;
}

So whether you use CSS-in-JS or not, you’re still going to need to resort to standard CSS at least some of the time.

Style dependencies

CSS-in-JS makes it simple to include styles with components. And this is actually a huge benefit. Nobody likes maintaining entirely separate file trees just for their CSS, or managing CSS files which live in completely separate locations to their corresponding JSX.

But now that we all have access to wonderful tools like Webpack and create-react-app, this benefit isn’t limited to CSS-in-JS. In fact, I place my LESS files right next to my JSX (or JS with Angular), and then include them like this:

import './DocumentForm.less'

As for managing dependencies between LESS files? There are a number of ways to do this. CSS Modules is the heavy duty option, but I prefer something much simpler:

@import (reference) '~my-less-util/cards.less';

That little (reference) ensures that no output is generated by the @import; it is just a way of importing variables and mixins. This allows each component’s CSS to be completely independent of the other components.

Composition of styles

Being able to compose classes to create larger, more specific classes is a powerful tool. Luckily, LESS and SCSS have been able to do this for what, maybe a decade? But if this is the case, why do people still act like composition with CSS is difficult?

The problem isn’t that the technology is lacking. The problem is that designing composable styles is bloody difficult. And as somebody who works with React, you’re probably intimately familiar with the difficulties of decomposing something into smaller, re-usable parts.

Trying to solve CSS composition with JavaScript is like trying to improve your social life with Facebook. It might make a difference, but only because it gives you a reason to actually try.

If you do want to learn more about designing composable styles, I recommend the excellent article by Adam Wathan, CSS Utility Classes and “Separation of Concerns”.

More Power

So this is a valid point. You do get more power with CSS-in-JS than you would from CSS or existing tools like LESS, SCSS or PostCSS. But do you really need it?

No website is complete without a terrible car analogy, so here I go: CSS is a moped. It sucks, but it is what you start out with. It is dangerous, slow, and it quickly teaches you why you need more power. LESS/SCSS is a Japanese car. It is reliable, it gets you where you need to go, it won’t need fixing any time soon, and it’ll still hit the speed limit if you want it to. CSS-in-JS is a sports car – it is damn good at one or two things, but it’ll spend a lot of time in the shop.

The ugly parts

If all CSS-in-JS did was provide new solutions to old problems, it’d actually be kind of interesting. Of course, like any new technology, it introduces its own problems too.

Security?!

When researching CSS-in-JS, this made me jump a little. From the styled-components documentation:

IE sometimes allows JavaScript to be embedded within CSS. This means that if you accidentally interpolate unfiltered user input into a stylesheet, you’re in all sorts of trouble.

Since styled-components allows you to use arbitrary input as interpolations, you must be careful to sanitize that input.

Yep. So not only do you need to remember to sanitize all your inputs, you need to make your designers do too. And then trust them to keep doing it. Otherwise you’ll open up your site or app to a fun array of XSS attacks and possibly even arbitrary JavaScript execution.

This is terrifying.

To be clear, this won’t be a problem unless you connect user input up to your styles. But will everybody on your team understand how important it is that you never allow stylesheet variables to be set by users?

A lot of people see the ability to use standard JavaScript variables in styles as a plus. But given the security implications, I’d say that missing out on shared variables is a blessing in disguise.

Read more about the security implication at my answer to How to use CSS-in-JS securely?.

Goodbye tooling

One of the things about most tooling for styling is that it expects the styles to be in stylesheet files. It may go without saying, but with CSS-in-JS, your styles are not in sylesheet files (at least during development).

This means that nothing will work. Or more specifically:

  • Syntax highlighting will not work, at least without some effort. And in some editors.
  • Linters will mostly not work.
  • Hot reloading styles will not work.
  • You can’t use LESS, SCSS or PostCSS – or any of your existing mixins.

And the best part? If you don’t want to use vogon poetry as class names during development, you’ll need to setup a babel plugin. Which will take you from classes that look like asdf123, to classes that look like sc-Button-asdf123 asdf123. So your development console is going to look like a mess.

Which style wins?

So you know how individual styles have priorities?

Element selectors have the lowest priority — you can override them with CSS classes. Which can be overriden with more classes. And classes can be overridden with IDs, which can in turn be overridden with !important.

Where do CSS-in-JS styles go?

That’s a great question! This will probably depend on the actual library, but at least with styled-components, they override all selectors that are made with a single class. So if you have this component:

<style>
.red-background {
  background-color: red;
}
</style>
<SomeStyledComponent className="red-background">

</SomeStyledComponent>

The actual background color may well be green. Cool, huh?

Designers speak CSS

While CSS, LESS and SCSS certainly have their flaws, they have one unbeatable feature: everybody knows them.

Let’s say you’re building an application with CSS-in-JS, and you want to hire a designer to put together some new pages for you. And for arguments sake, you know a few designers that have a working understanding of React.

But do they know React and JavaScript well enough to factor out functions where necessary, fix build system issues, and sanitize user inputs securely?

Maybe you do know some people like this – they do exist. But this doesn’t mean you know a designer, it means that you know a frontend god. And good for you. But don’t count on them being around forever.

The great part

CSS-in-JS does have a great part: it isn’t CSS.

There are times in a developer’s life where CSS isn’t actually an option. And while this may sound crazy at first, there is actually a relatively common situation where you’ll encounter this requirement:

You can’t use CSS in react-native apps. But you can use CSS-in-JS with styled-components.

So for all my ranting about CSS-in-JS, I don’t think it is a terrible technology. In fact, I think it is actually pretty cool.

But in my opinion? If more mature tools are an option, use them instead – at least for now.

More reading