Andrei Pfeiffer logo
Back to Articles

CSS-in-JS misconceptions

9 min read

In 2014, a new way to author CSS emerged, called CSS-in-JavaScript. The initial motivation for the technique was to fix the inherent scalability issues of CSS.

However, the first implementations were not perfect. Over the years, countless iterations were born, constantly improving and evolving CSS-in-JS authoring. Consequently, at the time of writing, there are more than 50 CSS-in-JS libraries out there.

This kind of iteration is crucial for the evolution of new technology. But unfortunately, this process backfires when trying to adopt CSS-in-JS, as it gets cumbersome to fully understand it.

Therefore, this article is focused on shedding some light regarding what CSS-in-JS is, but more importantly, what CSS-in-JS is not. If you have any preconceptions or doubts about any aspect of CSS-in-JS, then this content is for you:

Is CSS-in-JS for React only?

Short Answer

No. CSS-in-JS as a paradigm is framework agnostic.

Long Answer

While it's true that some CSS-in-JS libraries are specifically built for React, the large majority of them are framework agnostic. Any library that generates CSS class names can be used with any JavaScript framework, or with no framework at all:

import { css } from "goober";

// this will return a string representing a unique CSS class name
const title_styles = css({ color: "blue" });

// the class name can be applied as any regular CSS class
const template = `<h1 class="${title_styles}"> Title </h1>`

Additionally, JSS is the first CSS-in-JS library, which is also maintained today. Even though JSS added a React plugin later on, it was initially built without React in mind.

On the other hand, what is true is that CSS-in-JS is more prevalent within the React ecosystem, as there's no built-in solution for style encapsulation. For instance, Angular, Vue, or Svelte have built-in support for scoping styles. Therefore there aren't notable or popular implementations of CSS-in-JS libraries in other frameworks, at least as of May 2022.

Does CSS-in-JS use inline styles?

Short Answer

No, none of the currently existing CSS-in-JS libraries use inline styles as output.

Long Answer

Libraries like Radium and Glamor used inline styles, but both libraries have been discontinued.

Inline styles have limited support for CSS syntax, making it impossible to define certain pseudo-classes, pseudo-elements, or media queries. In addition, common pseudo-classes like :hover or :focus required sub-optimal workarounds by attaching DOM event listeners and triggering style updates using JavaScript.

The css prop method used by Emotion resembles inline styles definition, but under the hood, it actually generates unique CSS class names similar to CSS Modules or any other CSS-in-JS library.

/** @jsx jsx */
import { jsx } from '@emotion/react'

// the `css` prop will generate scoped CSS class names
const Title = <h1 css={{ color: "blue" }}>Title</h1>;

// > Output:
<h1 class="css-bp9m3j">Title</h1>

Does CSS-in-JS support all CSS syntax?

Short Answer


Long Answer

All modern CSS-in-JS libraries support the full CSS syntax. I have analyzed more than 10 libraries, focusing primarily on features such as pseudo-classes and elements, media queries, and keyframe animations.

Each library provides its own syntax and APIs to support the above features, but they generally have a low learning curve. As far as my knowledge and understanding go, there aren't any CSS syntax or features that CSS-in-JS does not support.

Is CSS-in-JS equivalent with styled components?

Short Answer

No. Styled components is only one of the CSS-in-JS libraries, which also popularized a revolutionary way to define styles, also called Styles components.

Long Answer

One of the popular libraries that use CSS-in-JS is called styled-components. Furthermore, they also introduced a new way to apply the JS styles to the desired HTML elements, a technique which is also called Styled components.

import { styled } from "styled-components";

// returns a new <Title /> component, with CSS class name attached
const Title = styled("h1")({ color: "blue" });

This approach eliminates the mapping between HTML elements and their styles, returning a new component with the CSS class name(s) already applied. This contrasts with the standard CSS approach, which implies defining the styles separately and attaching them to existing HTML elements. Other CSS-in-JS libraries, like Emotion, Goober, Stitches, or Compiled, also support this approach.

But in the end, a Styled component is only a technique to attach CSS styles to a DOM element or an existing component. There are alternative solutions for CSS-in-JS styles attachment if there's a reason for not using the Styled syntax.

Does CSS-in-JS enforce camelCase syntax?

Short Answer

No. Standard CSS syntax using kebab-case is also supported.

Long Answer

The object styles syntax, which uses camelCase CSS rules, is one way to define CSS-in-JS styles. The alternative is the tagged templates syntax, supported by libraries like styled-components, Emotion, Goober, and Compiled, allowing developers to write styles exactly like regular CSS.

import { css } from "goober";

// Goober's css() function also supports tagged templates
const title = css`
  background-color: blue;

What is true is that object syntax is the preferred method for CSS-in-JS styles definition, as it is simpler, more lightweight, and more optimal than template strings. As styles are eventually computed as JavaScript code, defining them directly as objects doesn't require additional string parsing.

Switching from regular CSS syntax using kebab-case properties to the object syntax using camelCase syntax might seem daunting. But in reality, you get the hang of it within days.

Is CSS-in-JS only for ignorants?

Short Answer

No. CSS-in-JS is simply another paradigm for scaling CSS, besides Semantic and Atomic CSS.

Long Answer

One recurring prejudice that you'll often find is that most developers that use CSS-in-JS don't really understand how CSS works.

Firstly, using CSS-in-JS without knowing regular CSS won't fill any language knowledge gaps. We'll use the same CSS rules, layout techniques, positioning options, and CSS units for values.

Secondly, let's think about styles encapsulation, to eliminate the need for manually managing CSS class names. If CSS-in-JS is only for ignorants, then we should also put CSS Modules, Shadow DOM, and Atomic CSS in the same bucket. In the end, what all of these paradigms and techniques are doing is removing the reliance on the CSS cascade and the global namespace.

On the contrary, fully understanding the pitfalls of the CSS cascade and global styles should determine us to circumvent them, especially in large scale applications.

Does CSS-in-JS break the separation of concerns?

Short Answer

No, not in the context of component-based architectures.

Long Answer

When this argument comes up, it typically refers to the separation of content (HTML), styles (CSS), and behavior (JS). This separation makes perfect sense when thinking of websites or applications where content is king, like blogs, documentation, presentational websites, etc.

React was the first library to put the HTML in JS in the form of JSX. Later on, React also popularized CSS in JS. The main reason for this is the component-based architecture that most JavaScript frameworks adopted. Components encapsulate content, styling, and behavior since all these concerns relate and depend on each other. They belong together, therefore it makes no sense to separate them.

This mindset is also adopted by Angular components, React Native StyleSheets, Vue Single-File Components, and Lit components. The reason is quite simple: code maintenance is essential when developing large applications.

Does CSS-in-JS require an additional build step?

Short Answer

Yes, as any other tool which uses non-standard features.

Long Answer

The only scenario which doesn't require a build step is when writing pure CSS, without CSS Processors. But, let's face it: if no such tools are needed, then it doesn't make sense to use CSS-in-JS, or any other scalable paradigms in the first place.

However, any CSS-related tooling requires some sort of processing, performed during one or more build steps. This includes CSS Processors, CSS Modules, Atomic CSS, etc.

Considering that any CSS-in-JS library already provides everything other tools offer, we would actually replace multiple build steps with a single one.

Does CSS-in-JS ship additional code?

Short Answer

It depends.

Long Answer

Most popular CSS-in-JS libraries, like styled-components, Emotion, JSS, and others output their styles as runtime stylesheets. They indeed require additional code to be shipped, which varies between 6kB and 18kB minified and gzipped.

However, there are also very lightweight CSS-in-JS solutions like Goober, which ships only 1kB of additional code.

Additionally, if that is still too much, there's always the alternative of static CSS extraction. This approach is implemented by vanilla-extract, which doesn't require any additional runtime code, having the same impact as plain old regular CSS.

Does CSS-in-JS require learning another library?

Short Answer

Yes, of course.

Long Answer

Well, this is undeniable. If we want to use a CSS-in-JS library, we'll have to learn its syntax.

However, when this argument is used against CSS-in-JS as a paradigm, we'll have to compare it with the alternatives:

  • Atomic CSS also requires us to learn a framework, not to mention that their surface is typically much larger.
  • Any CSS Methodology or architecture requires us to learn it, not to mention the constant effort of making sure everyone on the team applies it properly.
  • CSS Modules are usually used with a CSS Preprocessor, requiring us to learn not one, but two different libraries.

In the end, if we want to use any tools for managing CSS, we'll have to learn how to use them.

Does CSS-in-JS enforce styles colocation?

Short Answer

No. They can also be imported from separate files.

Long Answer

Not everyone agrees that styles belong in their respective component file. Fortunately, with CSS-in-JS, we can always move the styles in a separate file, just like any other JavaScript code:

import { css } from "goober";

// export styles
export const title = css({ color: "blue" });

... and import them in the component file, which resembles the usage of CSS Modules:

import * as styles from "./title.styles.js";

export function Title() {
  return <h1 className={styles.title}>Heading</h1>;

Therefore, we can colocate styles for relatively small components with CSS-in-JS, removing one layer of indirection. But we also have the flexibility to extract them in separate files.

On the other hand, with regular CSS, we have only one option.

The above list is not comprehensive. Therefore, if you have any other misconceptions that should be clarified, please get in touch. I would love to hear your thoughts.

In conclusion, CSS-in-JS shouldn't be judged from the perspective of a specific library. Instead, CSS-in-JS is a technique, a paradigm, and an alternative approach to classical CSS authoring.

Scroll to top