I think styled-components and emotion are great libraries for their purpose. Problem is, I don't think most developers are using them for that purpose.

To be clear, this won't be an argument for separation of technologies. Which, if you're already using a JavaScript library to render your view, you've probably come to terms with the idea that separation of technologies is not the same as separation of concerns.

CSS-in-JS does one thing really, really well: dynamic values in CSS.

I'm talking about actually dynamic values. Ones where something like simple class toggling won't work. If you're using CSS-in-JS to toggle between a few styles based on something like a boolean, you're using a sledgehammer to drive a nail.

const Button = styled.a` background: white; color: black; ${props => props.error && css` background: red; color: white; `} `;

The same functionality as just a simple classname switch:

const buttonClass = props.error ? 'button-error' : 'button-normal';

Truly dynamic values would be things like background image URLs, color codes, or number values in large ranges passed through props or other means.

Now I'm fully prepared for the gasps and pearl clutches that this next suggestion will elicit. If you only have a few limited situations where you do need dynamic CSS values, you can render inline styles rather than import an entire JS library dependency, or worse, convert all of your styles to work with that library.

But these aren't your grandfather's inline styles. We're already crossing the separation of technologies streams here so the normal reasons to avoid inline styles, like maintainability, aren't relevant. The biggest concern this alternative creates is the high specificity of inlined styles. But this is a dynamic value you're using purposefully, odds are you want the style to override any element/class inherited styles.

const backgroundImage = `url('${props.backgroundImageUrl}')`; return <div className="heroImage" style={backgroundImage} />;

Now that solution might not be for you. If you need a lot of dynamic CSS values then CSS-in-JS might be the right solution. But why use a solution to a specific problem as your entire solution to styling? Don't throw the baby out with the bathwater, you can use dynamic CSS values in your JS where you need them and still use CSS with classnames for the rest.

"The view that css-in-js is some magic solution to the classic problems of css is a misguided one." - Kye Hohenberger (tkh44)

emotion-js creator

(source)

I won't get into the merits of scoping vs properly and powerfully cascading your styles here, that's a conversation for another time. But if you are looking to scope your styles to your components CSS modules solves this. Again, CSS-in-JS should solve the problem of dynamic values in CSS, but the most common argument I see for its use is scoping, a side-effect of its use.

The CSS prop in emotion-js is the way to go if you're going to use CSS-in-JS and thankfully as of V4 styled-components also supports a variation of it. Looking at the JSX below it's difficult to grok which are markup/html elements created through styled components and which are "true" React components without tracking down its origins elsewhere in your files.

return ( <Container> <Headline>Hello World</Headline> <Status color="Green">Approved</Status> </Container> );

With the CSS prop (or classnames) there's a lot less muddying of the waters and it's immediately clear which element is a "true" component.

return ( <div css={container}> <h1 css={headline}>Hello World</h1> <Status color="Green">Approved</Status> </div> );

All in all CSS-in-JS can be a great tool when it's needed. Just don't replace CSS outright in your next project because of the current popularity of some of these libraries, and certainly don't leave CSS behind if all you want is scoped styles. At the end of the day our first love Sass will always be there for us.