The exact way that we write CSS for our web apps is a niche topic, and yet there is a huge amount of variety and discussion around it. Things have evolved a lot over the years. We started from a world preprocessors like Sass and Less, to CSS-in-JS libraries like Styled Components and Emotion, to CSS modules and finally to atomic CSS.
However, this journey has created some confusion and ill-defined terminology, and nothing is quite as bad as the term “CSS-in-JS”.
#The origin of this post
This short throwaway line for months ago is what led me to start writing this post. I stopped myself, thinking that I was overreacting, but I’ve since heard the same misconception from a lot of people and I figured it was important enough to write about and clarify things.
TLDR; Regardless of whether StyleX is CSS-in-JS or not, it does not have any issues with SSR or those kinds of things. If there is an issue, it might be the additional complexity of setting up your build pipeline correctly for StyleX, which something like Tailwind mostly side-steps by using a separate standalone process rather than integrating within the existing build pipeline.
#What is CSS-in-JS?
The term “CSS-in-JS” came about with early libraries such as Radium, Aphrodite, and Glamor. These libraries and their more modern counterparts like Styled Components and Emotion, all let you define your styles within your JavaScript (or TypeScript) files.
However, these libraries also injected the styles using Javascript at runtime. Some of them included ways to “server render” the styles, but none of them had a way to generate a static CSS file.
This started to change with the advent of libraries like Linaria, which let you define you styles with mostly the same syntax as Emotion, but instead of injecting the styles at runtime, it would generate a static CSS file.
So, the question arises, what is CSS-in-JS?
And the answer is that, as a community, we have never really defined it. In one definition, it is anything that injects CSS at runtime. In another definition, it is anything that that gives you the ability to write CSS in your JavaScript files.
And so, the question really becomes, do we care about how it works, or how it looks?
#It’s how it works
If you’re in the camp that would like to define CSS-in-JS, based on how it works, then of course, Tailwind is not CSS-in-JS. Neither is Linaria and nor is StyleX.
None of these libraries use runtime injection of CSS. Although all three work in different ways, they all generate a static CSS file at build time. And when comparing Tailwind and StyleX, they result in shockingly similar code with the mostly same performance characteristics.
And so, when you hear people say, “CSS-in-JS is dead”, they aren’t talking about Linaria, Tailwind or StyleX. They’re talking about the libraries that inject CSS at runtime.
#It’s how it looks
If, however, you’re in the camp of how it looks, then you would consider Linaria and StyleX to be CSS-in-JS. In that case, however, I would argue that Tailwind is CSS-in-JS, too.
Just like other CSS-in-JS libraries, Tailwind lets you define your styles directly within your JavaScript files. The syntax is different. Instead of using CSS syntax in template strings like Linaria, or JavaScript objects like StyleX, Tailwind uses a special syntax made of special classNames, but it is still very much a syntax where you’re able to write arbitrary styles with arbitrary values.
Back in the days of Tailwind 1 and 2, you could make the argument that this wasn’t the case, but ever since
the Tailwind JIT and support for syntax as such as []
for adding arbitrary values, Tailwind is
very much CSS-in-JS.
#Tailwind is bad at being CSS-in-JS
While Tailwind is very much CSS-in-JS, as a syntax, it’s not very good at being CSS-in-JS. While the className abstraction is great for quickly prototyping styles, it falls apart outside of the common use-cases. Writing CSS keyframes, view transitions, anchor positioning and anything out of the ordinary means reaching for an actual CSS file.
This syntactic limit isn’t particularly problematic for devX. It just forces you to think in two different paradigms for different styles in your codebase.
However, it does create some friction when choosing how to generate the static CSS files for particularly large applications.
#Conclusion
I don’t really care about the definition of CSS-in-JS. The industry is rapidly moving away from anything that injects CSS at runtime. The performance penalty is well known, and even those using libraries like Emotion or Styled Components are starting to migrate to newer solutions that generate static CSS files.
However, if the only reason you’ve been scared of using StyleX (or even Linaria) is because you’ve heard all the bad things about CSS-in-JS, then you can rest easy. Either StyleX isn’t CSS-in-JS, or Tailwind is.