The State of CSS-in-JS in 2026: Is It Dead?
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:
- Server Components can't use them — RSC runs on the server, no browser context for style injection
- Bundle size — styled-components adds ~50KB gzipped; Emotion adds ~15KB
- Flash of unstyled content — server renders HTML, then client re-injects styles
- 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:
- Design systems — Material UI (Emotion) and Chakra UI (Emotion) are still widely used
- Dynamic theming at runtime — Changing themes based on user preferences stored in DB
- Existing codebases — The cost of rewriting Emotion to Tailwind is rarely worth it
- React Native — StyleSheet API is CSS-in-JS-like; StyleSheet.create is idiomatic
- 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
| Library | Runtime | RSC Support | Bundle Add | DX | Adoption 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 | ✅ Perfect | 0 (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.
See the live comparison
View styled components vs. emotion on PkgPulse →