Skip to main content

The State of CSS-in-JS in 2026: Is It Dead?

·PkgPulse Team

TL;DR

CSS-in-JS isn't dead — but the runtime model is. Styled-components (~7M weekly downloads) and Emotion (~9M) still dominate by download count, but most are from legacy codebases. New projects in 2026 overwhelmingly choose Tailwind CSS (~12M), CSS Modules, or zero-runtime CSS-in-JS tools like Panda CSS and StyleX. The shift is clear: runtime CSS injection (bad for React Server Components, adds KB to bundles, blocks rendering) is being replaced by build-time extraction.

Key Takeaways

  • Emotion: ~9M weekly downloads — peaked in 2023, declining for new projects
  • styled-components: ~7M downloads — RSC-incompatible, v6 had migration pain
  • Tailwind CSS: ~12M downloads — the winner; utility-first now the default DX
  • Panda CSS: ~200K downloads — zero-runtime, TypeScript-first, RSC-compatible
  • StyleX: ~100K downloads — Meta's build-time CSS, atomic classes, performance-first

What Happened to CSS-in-JS?

The death knell arrived with React Server Components in 2023-2024. Runtime CSS-in-JS libraries like styled-components and Emotion inject styles via JavaScript at runtime — which means:

  1. Server Components can't use them — RSC runs on the server, no browser context for style injection
  2. Bundle size — styled-components adds ~50KB gzipped; Emotion adds ~15KB
  3. Flash of unstyled content — server renders HTML, then client re-injects styles
  4. Streaming incompatibility — style injection conflicts with React 18's streaming SSR

By 2025, the Emotion and styled-components teams explicitly acknowledged these limitations. styled-components v6 dropped some workarounds that broke many codebases mid-migration.


The Winners: What's Replacing CSS-in-JS

1. Tailwind CSS (The Dominant Replacement)

// Tailwind — utility classes, zero runtime
function PackageCard({ pkg }: { pkg: Package }) {
  return (
    <div className="rounded-xl border border-gray-200 bg-white p-6 shadow-sm
                    hover:shadow-md transition-shadow duration-200
                    dark:border-gray-700 dark:bg-gray-800">
      <div className="flex items-center justify-between">
        <h3 className="text-lg font-semibold text-gray-900 dark:text-white">
          {pkg.name}
        </h3>
        <span className={`rounded-full px-2 py-0.5 text-xs font-medium
          ${pkg.health >= 80 ? 'bg-green-100 text-green-700' :
            pkg.health >= 60 ? 'bg-yellow-100 text-yellow-700' :
            'bg-red-100 text-red-700'}`}>
          {pkg.health}/100
        </span>
      </div>
      <p className="mt-2 text-sm text-gray-500 line-clamp-2">{pkg.description}</p>
    </div>
  );
}

Tailwind outputs a static CSS file at build time — no runtime, no JS, works in RSC, works everywhere.

2. CSS Modules (The Quiet Standard)

// CSS Modules — scoped CSS, zero runtime, RSC-compatible
// PackageCard.module.css
// .card { border-radius: 12px; background: white; ... }
// .health-good { color: green; }
// .health-bad { color: red; }

import styles from './PackageCard.module.css';

function PackageCard({ pkg }) {
  return (
    <div className={styles.card}>
      <span className={pkg.health >= 80 ? styles['health-good'] : styles['health-bad']}>
        {pkg.health}/100
      </span>
    </div>
  );
}

CSS Modules are fully supported in Next.js, Vite, and every major bundler. Zero runtime, true scoping.

3. Panda CSS (Zero-Runtime CSS-in-JS)

// Panda CSS — write like CSS-in-JS, output like Tailwind
import { css } from '../styled-system/css';
import { stack, hstack } from '../styled-system/patterns';

function PackageCard({ pkg }) {
  return (
    <div className={css({
      rounded: 'xl',
      border: '1px solid',
      borderColor: 'gray.200',
      bg: 'white',
      p: 6,
      shadow: 'sm',
      _hover: { shadow: 'md' },
      _dark: { borderColor: 'gray.700', bg: 'gray.800' },
    })}>
      <div className={hstack({ justify: 'space-between' })}>
        <h3 className={css({ textStyle: 'lg', fontWeight: 'semibold' })}>
          {pkg.name}
        </h3>
      </div>
    </div>
  );
}

// At build time, Panda extracts static CSS — no runtime JS
// Output: compiled atomic classes like Tailwind

Panda CSS is the spiritual successor to CSS-in-JS for teams who loved the API but need RSC compatibility.

4. StyleX (Meta's Approach)

// StyleX — build-time, atomic, predictable
import * as stylex from '@stylexjs/stylex';

const styles = stylex.create({
  card: {
    borderRadius: '12px',
    backgroundColor: { default: 'white', '@media (prefers-color-scheme: dark)': '#1f2937' },
    padding: '24px',
    boxShadow: { default: '0 1px 3px rgba(0,0,0,0.1)', ':hover': '0 4px 6px rgba(0,0,0,0.1)' },
  },
  healthGood: { color: 'green' },
  healthBad: { color: 'red' },
});

function PackageCard({ pkg }) {
  return (
    <div {...stylex.props(styles.card)}>
      <span {...stylex.props(pkg.health >= 80 ? styles.healthGood : styles.healthBad)}>
        {pkg.health}/100
      </span>
    </div>
  );
}

StyleX outputs atomic CSS at build time. Meta uses it to style facebook.com — performance at extreme scale.


Download Trend Analysis

styled-components weekly downloads:
2023: 8.5M  → 2024: 7.5M  → 2026: 6.8M  (-20% over 3 years)

Emotion weekly downloads:
2023: 10M   → 2024: 9.5M  → 2026: 9.1M  (-9%, more stable due to MUI)

Tailwind CSS weekly downloads:
2023: 6M    → 2024: 9M    → 2026: 12M   (+100% over 3 years)

Panda CSS:
2024: 80K   → 2026: 200K  (+150%)

Vanilla Extract:
2023: 400K  → 2026: 450K  (stable)

The transition is happening — just slower than predicted because legacy codebases don't rewrite themselves.


When CSS-in-JS Still Makes Sense

Not everything is RSC. CSS-in-JS is still the right choice for:

  1. Design systems — Material UI (Emotion) and Chakra UI (Emotion) are still widely used
  2. Dynamic theming at runtime — Changing themes based on user preferences stored in DB
  3. Existing codebases — The cost of rewriting Emotion to Tailwind is rarely worth it
  4. React Native — StyleSheet API is CSS-in-JS-like; StyleSheet.create is idiomatic
  5. Client-only apps (no SSR) — Runtime injection is fine if you don't SSR/RSC

The Decision Tree for 2026

New project?
├── Uses React Server Components → Tailwind or CSS Modules
├── Heavy theming / design system → Panda CSS or StyleX
├── Familiar with Tailwind → Tailwind
└── Small team, scoped styles → CSS Modules

Existing project?
├── styled-components / Emotion working fine → Keep it
├── Migrating to RSC → Evaluate Tailwind or Panda CSS
└── Performance issues → Profile first; consider Tailwind migration

Comparison Table

LibraryRuntimeRSC SupportBundle AddDXAdoption Trend
styled-components✅ Yes❌ Limited~50KB⭐⭐⭐⭐↓ Declining
Emotion✅ Yes❌ Limited~15KB⭐⭐⭐⭐↓ Slight decline
Tailwind CSS❌ None✅ Perfect~10KB (CSS)⭐⭐⭐⭐⭐↑ Rising fast
Panda CSS❌ None✅ Perfect~5KB (CSS)⭐⭐⭐⭐↑ Rising
StyleX❌ None✅ Perfect~5KB (CSS)⭐⭐⭐↑ Rising
CSS Modules❌ None✅ Perfect0 (CSS)⭐⭐⭐→ Stable
Vanilla Extract❌ None✅ Perfect~5KB⭐⭐⭐→ Stable

Verdict: CSS-in-JS isn't dead, but the runtime model is on life support for new projects. Tailwind won the DX battle. Build-time CSS-in-JS (Panda, StyleX, Vanilla Extract) is the future for teams that want CSS-in-JS ergonomics with modern constraints.


Compare CSS library package health on PkgPulse.

Comments

Stay Updated

Get the latest package insights, npm trends, and tooling tips delivered to your inbox.