Suraj Vishwakarma I am an enthusiastic programmer who loves to write code and blog posts so that others can understand technology.

Comparing the top zero-runtime CSS-in-JS libraries

8 min read 2416

Comparing The Top Zero-Runtime CSS-In-JS Libraries

Editor’s note: This article was last updated on 1 September 2023 to incorporate information about the vanilla-extract and Treat runtime libraries, as well as to update the code segments relating to the Linaria library.

Web developers often search for repositories on GitHub to contribute to. However, once they find an exciting project and start contributing, a common challenge they face is finding the specific style definitions of the project, especially in large projects.

Fortunately, there’s a simple solution for this: web developers should define components and styles in the same project file. The CSS-in-JS syntax technique is used to write components and styles in the same file while maintaining simplicity and clarity.

According to styled-components creator Max Stoiber, more than 60 percent of React installs also install a CSS-in-JS library. Writing CSS in JavaScript is extremely popular, especially when using a JS framework like React or Angular. Many libraries are available to simplify your process of writing CSS-in-JS. In this article, we’ll review some of the most popular options.

Jump ahead:

What is CSS-in-JS?

CSS-in-JS is a styling technique where components are styled directly by using JavaScript. We use variables to define the CSS of the component. The variable will contain all the CSS properties, ensuring that the component is seamlessly wrapped with its specified styles.

CSS-in-JS has increased in recent times as component-based styling has also become more popular. And as most of the modern JavaScript frameworks are component-based, this fuels the increased usage of CSS-in-JS. CSS has now become a module of JavaScript that can be defined and used whenever necessary.

In a modern framework like React, you can use the inline technique to write CSS in the JSX section of your JavaScript file for by writing CSS-in-JS. But this technique can be confusing, less readable, and can break the flow of code. It can’t replace the modularity of CSS while writing CSS-in-JS through libraries.

Using CSS-in-JS

In CSS-in-JS, we define styles in a variable, which we can then use to style the components by wrapping them with the variable tag.

The styled tag is imported from the library. It creates a React component with pre-defined styles, followed by the HTML tag that you want to use. In the example below, we use h1, which will be customized according to the defined CSS properties. After coding this, we then define the properties like so:

const Title = styled.h1`
  font-family: sans-serif;
  font-size: 48px;
  color: #f15f79;

Next, we wrap the contents within the variable tag:

const App = () => <Title>Hello world!</Title>;

Viola! This is how you define the styles in most CSS-in-JS libraries. Now that we’ve covered the basics, let’s look at some advantages of using CSS-in-JS.

Advantages of using CSS-in-JS

  • Easy code sharing: Sharing code is easier and more efficient with CSS-in-JS as others can easily understand your code instead of trying to find components and styles within the project
  • Less load on the DOM: Because we define CSS and components in the same file, the CSS for the component will load only when the component loads, reducing the unnecessary load on the virtual DOM
  • Using JavaScript in CSS: Because the CSS is defined within the JavaScript file, we can use complex JavaScript logic to define the value of CSS properties
  • Better error handling in CSS: Because the CSS also undergoes the compiling process, we will receive error messages as it does so, making it easy to find and solve bugs within CSS
  • Portability: Having style and components in the same file makes it easy to use the component in other projects

Disadvantages of using CSS-in-JS

There are a few downsides to using CSS-in-JS, including:

  • Because styling is defined in the JavaScript file, it will affect the styling of the component if JavaScript is disabled
  • Styles are double-parsed, once by the library and then by the browser when styles are inserted
  • Traditionally, when we load a webpage, a browser just reads the CSS and applies it. When using CSS-in-JS, the browser dynamically generates a CSS style tag, then reads and applies it to the webpage. Reading and generating this costs performance time

Compile time vs. runtime

High-level programming languages designed for developing applications are usually created for humans to read and understand. For a machine to understand code written in a high-level language like JavaScript or Python, the code needs to be transformed by a compiler or interpreter into low-level, machine-readable code.

Compile time refers to the time when code written in a high-level, human-readable language is transformed by a compiler into a low-level, machine-readable code. Runtime, on the other hand, refers to the time when a program’s transformed code is running on the end user’s machine.

One of the solutions to improving lost performance time due to double parsing is that the libraries can convert the CSS-in-JS block into a separate CSS file first. Then, the browser will read and apply those styles to the webpage, ultimately saving runtime that’s typically wasted while generating a style tag. This is called zero-runtime CSS-in-JS. It is particularly useful for scaled or complex projects where performance is key.

To achieve zero-runtime CSS-in-JS, there are various libraries you can make use of. In the following sections, we’ll introduce some of the most popular ones to consider.


Linaria Logo

Written in TypeScript, Linaria is the most popular zero-runtime library, with 10.8k GitHub stars and 429 GitHub forks. It’s my personal favorite to use because it has an easy-to-use syntax and is compatible with almost every modern framework. Linaria converts the CSS-in-JS into a separate .css file while creating the build for production.

Linaria offers many features, including:

  • Dynamic prop-based style: You can use a prop to define the value of CSS properties
  • CSS source map: In large projects, it can be difficult to find where the style is defined for the component. If the CSS source map is defined true while writing CSS, it will show the source of the class name of generated CSS in dev tools
  • Linting CSS: Stylelint will help you to avoid any CSS errors and enforce conventions in your styles
  • JavaScript for logic: With Linaria, you can use JavaScript logic while writing CSS

Install Linaria from the npm package registry like so:

npm i @linaria/core @linaria/react @linaria/babel-preset

And here’s how you can use Linaria in your project:

import { css } from "@linaria/core";
import { modularScale, hiDPI } from "polished";
import fonts from "./fonts";

// Write your styles in `css` tag
const header = css`
  text-transform: uppercase;
  font-family: ${fonts.heading};
  font-size: ${modularScale(2)};
  ${hiDPI(1.5)} {
    font-size: ${modularScale(2.5)};

// Then use it as a class name
<h1 className={header}>Hello world</h1>;

Disadvantages of using Linaria:

  • Difficult to implement: Implementing Linaria properly can be difficult, as it requires setting up Babel
  • Setting up the bundler: Extracting CSS from a JS file requires using a bundler, such as Rollup or webpack, which can be difficult to set up


Astroturf Logo

Astroturf is a great alternative to Linaria. With more than 2.2k stars on GitHub, Astroturf helps you achieve zero runtime by keeping CSS fully static with no runtime parsing. With Astroturf’s scoped stylesheet, React, and props and component variants, there are several ways to write CSS-in-JS. See the implementation here.

The key features of Astroturf include:

  • Flexibility: Some frameworks only work with certain CSS processing, but Astroturf is flexible and compatible with most frameworks
  • Props support: Astroturf supports the props features of React to style components according to props
  • The ability to use your existing tools: You can use Sass and PostCSS to write style definitions in the JavaScript

Install Astroturf from npm with the following command:

npm i astroturf

Here’s how you can use Astroturf in your project:

import React from "react";
import { css } from "astroturf";

const btn = css`
  color: black;
  border: 1px solid black;
  background-color: white;

export default function Button({ children }) {
  return <button className={btn}>{children}</button>;

Disadvantages of Astroturf:

  • Poor documentation: Astroturf lacks a proper README on GitHub. It also lacks contribution guidelines, and the documentation is short, often leaving out important details
  • Implementation: For extracting styles, Astroturf requires bundlers such as Rollup or webpack, which can be difficult to implement


Reshadow Website

Written in JavaScript, Reshadow has 364+ stars on GitHub. This library offers many features, most notably delivering a shadow DOM developer experience for virtual DOM-like frameworks such as React. It also supports the CSS-in-JS syntax.

Reshadow offers the following features:

  • The benefit of PostCSS: With Reshadow, you will have access to all the benefits of PostCSS to automate routine CSS operations
  • Static styles: Reshadow provides an option to extract all your CSS-in-JS, consolidating them into a singular .css file
  • CSS module: You can use a CSS module to define the CSS, just as we do in JavaScript

First, install Reshadow from npm:

npm i reshadow

And here’s how to use it in your project:

import styled, { css } from "reshadow";

const styles = css`
  button {
    font-size: 16px;
    cursor: pointer;
    padding: 10px 15px;
    border-radius: 20px;
    border: 2px solid;
    background-color: white;
    color: darkorange;

const Button = ({ children, ...props }) =>
  styled(styles)(<button {...props}>{children}</button>);

Disadvantages of Reshadow:

  • Poor documentation and content: There’s very little content on the web about Reshadow, and the docs aren’t very thorough. As a result, learning takes time and can be difficult
  • Fewer contributors: There are few contributors to Reshadow, which slows down the process of solving issues that are attached to its GitHub repository



vanilla-extract is another popular zero-runtime CSS-in-JS library with over 8.7k stars on GitHub. It is framework agnostic, which means that you can use it with vanilla JavaScript or any frontend framework.

With vanilla-extract, you can write locally scoped styles and variables in JavaScript or Typescript and generate CSS files at build time. It also offers an optional API for dynamically theming your application.

Some of the features and benefits of vanilla-extract include:

  • Support for bundlers: It has integration for most popular frontend React frameworks and tools like webpack, Vite, Parcel, and Babel
  • Well-documented
  • Easy setup
  • Offers both JavaScript and TypeScript support
  • Type safety: It offers fully-typed API, improving the developer experience

To start using vanilla-extract, install it from the npm package registry:

npm install @vanilla-extract/css

You need to declare your styles in .css.ts or .css.js files when working with vanilla-extract:

import { style, globalStyle } from "@vanilla-extract/css";

export const buttonStyles = style({
  backgroundColor: "#1e4db6",
  color: "#fff",
  padding: "10px 20px",
  borderRadius: "5px",
  border: "none",

globalStyle("body", { backgroundColor: "#eee", margin: 0 });

Import the style you have declared from the .css.ts or .css.js file and apply it using the class attribute (or className, if you’re using React) like in the example below:

import { useState } from "react";
import { buttonStyles } from "./app.css";

function App() {
  const [count, setCount] = useState(0);
  return (
    <button className={`${buttonStyles}`} onClick={() => setCount(count + 1)}>
      Count: {count}

export default App;

Disadvantages of vanilla-extract:

  • Not actively maintained: There is a high number of open issues and pull requests, some of which are over a year old. This is a sign that vanilla-extract may not be actively maintained


Treat Package

Treat is another popular zero-runtime CSS-in-JS package with over 1.2k stars on GitHub. Like the other packages discussed above, when using Treat, styles are declared in .treat.js or .treat.ts files. Treat executes the .treat.js files and generates all CSS rules at build time, bundling only the generated CSS styles.

If you are using the theming feature, Treat generates all the CSS styles at build time. It then swaps the pre-generated classes at runtime when switching themes.

While Treat offers native support for React and TypeScript, its core API can be integrated into other frameworks, making it framework agnostic.

Some of the benefits of using Treat include:

  • Good documentation
  • Themeable: Treat has a built-in theming feature
  • Type safety: Treat comes with built-in type safety

You can install Treat from npm like so:

npm i treat

After installation, you can declare your styles in a .treat.js or .treat.ts file like this:

import { style } from 'treat';

export const buttonStyle = style({
  backgroundColor: "#1e4db6",
  color: "#fff",
  padding: "10px 20px",
  borderRadius: "5px",
  border: "none",

You can then import the styles you have declared into your component, like in the example below. This example assumes you’re using React:

import React from 'react';
import { buttonStyle } from './Button.treat';

export const Button = () => {
  return <button className={buttonStyle}>Click me</button>

Disadvantages of Treat:

  • Webpack setup: Treat requires webpack, which may be difficult to set up
  • Limited out-of-the-box support for frontend frameworks


Goober Package

Goober is a popular, lightweight, zero-dependency package. While it isn’t strictly a zero-runtime CSS-in-JS solution, its built-in extractCss function allows you to extract static CSS files and inject them into the <head> tag as you would in zero-runtime CSS-in-JS packages during server-side rendering.

The advantages of using Goober include:

  • Bundle size: Goober is lightweight (about 1kb)
  • Framework support: Goober is framework-agnostic

You can install Goober from npm with this command:

npm i goober

You can then inject the styles into your server-rendered code like so:

const express = require("express");

const { styled, extractCss, setup } = require("goober");
const preact = require("preact");
const render = require("preact-render-to-string");

const app = express();

const Button = styled("button")`
  background-color: #1e4db6;
  color: #fff;
  padding: 10px 20px;
  border: none;
  border-radius: 10px;

const App = () => preact.h(Button, null, "Click me!");

app.get("/", (_, res) => {
  const app = render(preact.h(App));
  const style = extractCss();

  const html = `
    <!DOCTYPE html>
    <html lang="en">
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <style id="_goober">

app.listen(process.env.PORT || 3000);

Disadvantages of Goober:

  • Not technically a zero-runtime CSS-in-JS
  • Setup: It requires Babel or webpack, which can be difficult to set up
  • Support for other bundlers: Goober doesn’t have out-of-the-box integration for some bundlers


Zero-runtime CSS-in-JS libraries offer many benefits, especially when developers are contributing to multiple or large projects. The future of CSS-in-JS is bright, especially when it comes to web development and modern frameworks. I hope you will add one of these libraries when you initiate your next project.

Get set up with LogRocket's modern error tracking in minutes:

  1. Visit to get an app ID
  2. Install LogRocket via npm or script tag. LogRocket.init() must be called client-side, not server-side
  3. $ npm i --save logrocket 

    // Code:

    import LogRocket from 'logrocket';
    Add to your HTML:

    <script src=""></script>
    <script>window.LogRocket && window.LogRocket.init('app/id');</script>
  4. (Optional) Install plugins for deeper integrations with your stack:
    • Redux middleware
    • NgRx middleware
    • Vuex plugin
Get started now
Suraj Vishwakarma I am an enthusiastic programmer who loves to write code and blog posts so that others can understand technology.

Leave a Reply