CSS-in-JS vs Legacy CSS: The Decisive Verdict
Co-located runtime styling versus plain stylesheets and modern CSS — which one you should actually ship in 2026.
The short answer
Legacy Css over Css In Js for most cases. Native CSS grew up while CSS-in-JS spent five years fighting the runtime tax it created.
- Pick Css In Js if locked into a heavily dynamic, theme-everything design system on a client-rendered SPA where styles genuinely depend on runtime props, and your team already has the muscle memory
- Pick Legacy Css The Decisive Verdict if want fast paints, minimal JS, RSC/SSR compatibility, and styles a junior can read six months from now — i.e. almost everyone
- Also consider: Build-time CSS-in-JS (vanilla-extract, Linaria) or utility CSS (Tailwind) as the honest middle ground — co-location without the runtime tax
— Nice Pick, opinionated tool recommendations
The runtime tax is real and you pay it on every render
Runtime CSS-in-JS libraries like styled-components and Emotion serialize styles, hash them, and inject <style> tags while the browser is trying to paint. That's main-thread work your users feel as jank, especially on mid-tier Android. Emotion's own maintainers and the React team have spent years documenting how this fights concurrent rendering and Server Components — styled-components went into maintenance mode in 2024, which tells you where the wind blows. Legacy CSS does none of this: the stylesheet is a static file the browser parses once, in parallel, off the main thread. You ship a .css file instead of kilobytes of JS that recompute styles on prop changes. The dirty secret is that most 'dynamic' styles aren't — they're three theme variants and a couple of states that CSS custom properties handle natively. You bought a runtime engine to solve a problem variables already solved.
Modern CSS ate CSS-in-JS's lunch
Every headline reason to adopt CSS-in-JS has a native answer now. Scoped styles? CSS Modules and @scope. Avoiding specificity wars? @layer cascade layers, which give you deterministic ordering without !important roulette. Co-locating logic-driven styles? Custom properties you set inline from JS — one line, zero runtime library. Nesting, the ergonomic win Sass and styled-components sold for a decade, is now baked into the platform. Container queries and :has() do layout-aware styling that JS-in-CSS never managed cleanly. The gap that justified the whole category in 2017 has effectively closed. What's left for runtime CSS-in-JS is a narrow band of genuinely render-dependent styling — and even there, CSS variables driven from React cover most of it. You don't need a 12KB dependency and a Babel plugin to change a color based on state.
Server Components are an extinction event for runtime styling
This is the part the CSS-in-JS holdouts don't want to discuss. React Server Components and Next.js App Router default everything to the server, and runtime CSS-in-JS fundamentally cannot run there — it needs the client to inject styles, so every styled component forces a 'use client' boundary. You bleed the exact server-rendering benefit you adopted the framework for. The official Next.js docs literally list styled-components and Emotion as needing workarounds, while plain CSS, CSS Modules, and Tailwind 'just work.' That's not a tooling rough edge; it's the framework telling you which way the ecosystem is going. If you're starting a React project in 2026 and reaching for a runtime CSS-in-JS library, you're adopting a pattern the framework authors are actively routing around. Legacy CSS and its build-time cousins are aligned with the platform's direction. Runtime CSS-in-JS is fighting it.
Where CSS-in-JS still earns its keep — and the honest middle
Credit where due: CSS-in-JS solved real 2017 problems — global namespace collisions, dead-style accumulation, no scoping. If you have a mature design-token system with deeply prop-driven theming on a pure client SPA, and a team fluent in it, ripping it out is a worse use of time than living with the runtime cost. But notice the escape hatch nobody talks about: build-time CSS-in-JS. vanilla-extract and Linaria give you co-located, type-safe, component-scoped styles that compile to static .css with zero runtime. That's the actual winner if you love the authoring ergonomics — you keep co-location and lose the tax. Tailwind is the other pragmatic answer for teams who want speed over purity. So the real fight isn't CSS-in-JS vs legacy CSS; it's runtime vs build-time. Runtime lost. Pick legacy CSS, modern native CSS, or a zero-runtime build-time engine, and stop paying for style recomputation.
Quick Comparison
| Factor | Css In Js | Legacy Css The Decisive Verdict |
|---|---|---|
| Runtime cost | Serializes and injects styles on render; main-thread work, fights concurrent rendering | Static stylesheet parsed once, off main thread, zero per-render cost |
| Server Components / SSR fit | Forces client boundaries; needs workarounds in Next.js App Router | Works natively on the server, no 'use client' tax |
| Dynamic / prop-driven styling | First-class, styles can depend on any JS value at render time | Handled via CSS custom properties and data attributes; covers most but not all cases |
| Scoping & specificity control | Automatic scoping, no global collisions | CSS Modules, @scope, and @layer now match it natively |
| Bundle & dependency weight | Adds a runtime library plus often a Babel/SWC plugin | Ships a .css file, no JS dependency |
The Verdict
Use Css In Js if: You're locked into a heavily dynamic, theme-everything design system on a client-rendered SPA where styles genuinely depend on runtime props, and your team already has the muscle memory
Use Legacy Css The Decisive Verdict if: You want fast paints, minimal JS, RSC/SSR compatibility, and styles a junior can read six months from now — i.e. almost everyone
Consider: Build-time CSS-in-JS (vanilla-extract, Linaria) or utility CSS (Tailwind) as the honest middle ground — co-location without the runtime tax
Css In Js vs Legacy Css The Decisive Verdict: FAQ
Is Css In Js or Legacy Css The Decisive Verdict better?
Legacy Css is the Nice Pick. Native CSS grew up while CSS-in-JS spent five years fighting the runtime tax it created. Cascade layers, nesting, container queries, and :has() killed most of the reasons people reached for runtime styling, and the React Server Components era openly punishes runtime CSS-in-JS. Legacy CSS — plain stylesheets or a build-time engine — ships less JavaScript, hydrates faster, and never blocks your first paint on a serialized style object.
When should you use Css In Js?
You're locked into a heavily dynamic, theme-everything design system on a client-rendered SPA where styles genuinely depend on runtime props, and your team already has the muscle memory
When should you use Legacy Css The Decisive Verdict?
You want fast paints, minimal JS, RSC/SSR compatibility, and styles a junior can read six months from now — i.e. almost everyone
What's the main difference between Css In Js and Legacy Css The Decisive Verdict?
Co-located runtime styling versus plain stylesheets and modern CSS — which one you should actually ship in 2026.
How do Css In Js and Legacy Css The Decisive Verdict compare on runtime cost?
Css In Js: Serializes and injects styles on render; main-thread work, fights concurrent rendering. Legacy Css The Decisive Verdict: Static stylesheet parsed once, off main thread, zero per-render cost. Legacy Css The Decisive Verdict wins here.
Are there alternatives to consider beyond Css In Js and Legacy Css The Decisive Verdict?
Build-time CSS-in-JS (vanilla-extract, Linaria) or utility CSS (Tailwind) as the honest middle ground — co-location without the runtime tax
Native CSS grew up while CSS-in-JS spent five years fighting the runtime tax it created. Cascade layers, nesting, container queries, and :has() killed most of the reasons people reached for runtime styling, and the React Server Components era openly punishes runtime CSS-in-JS. Legacy CSS — plain stylesheets or a build-time engine — ships less JavaScript, hydrates faster, and never blocks your first paint on a serialized style object.
Related Comparisons
Disagree? nice@nicepick.dev