CSS-in-JS — An Honest Look at a Declining Pattern

CSS Frameworks

Chapter 8 · CSS-in-JS — An Honest Look at a Declining Pattern

This chapter covers a fourth real pattern this course hasn't touched yet — and gives it the same honest, two-sided treatment applied throughout, rather than ignoring it or dismissing it.

What CSS-in-JS Actually Is

const Button = styled.button`
  background: blue;
  padding: 1rem;
`;

CSS-in-JS means writing actual CSS rules directly inside JavaScript or component files (styled-components, Emotion) — a component's own styling lives literally alongside its own logic in the same file, generated at runtime by a library that dynamically creates and injects real <style> rules into the page as components render. This looks like writing plain CSS, but it's actually a JavaScript template literal being processed by a library.

Why This Was Genuinely Popular — The Real Motivations

Worth being fair and honest here: CSS-in-JS wasn't a bad idea everyone was fooled by. It solved real problems when it became popular, in the mid-to-late 2010s alongside React's own rise. True component-scoped styles with no risk of global CSS collision at all — a genuinely stronger guarantee than BEM's own naming-convention-based scoping, since it's enforced by the tooling itself rather than developer discipline. And dynamic styling based on component props or state felt genuinely natural (background: ${props => props.primary ? 'blue' : 'gray'}), since styles and logic already lived in the same file and language. For a real period, this was considered a genuinely leading-edge, sophisticated approach — not a mistake.

The Real, Documented Reasons for Its Decline

The central, real technical reason is runtime cost. Classic CSS-in-JS libraries generate and inject styles at runtime, in the browser, as components render — a genuine, measurable JavaScript execution cost, and a genuine risk of a delay before styles are actually applied (a real, documented "flash of unstyled content" in some setups). This is a direct, structural contrast with every other paradigm this course has covered: Tailwind's own JIT (cssfw1-4) generates CSS at build time, Bootstrap ships precompiled CSS, headless libraries (cssfw1-6) ship zero styles at all. Classic CSS-in-JS is genuinely the only paradigm in this entire course that does real styling work in the browser, at runtime, rather than ahead of time.

"Zero-runtime" CSS-in-JS successor tools (vanilla-extract, some newer Emotion configurations) emerged specifically to fix this — extracting styles to real, static CSS at build time instead, closing the exact gap. Worth an honest, dated note: the CSS-in-JS story itself evolved once this problem became well understood, rather than the entire idea being abandoned outright.

The Shift Toward Utility-First / Zero-Runtime Approaches

Tailwind's own real rise (cssfw1-2 through cssfw1-4) is directly connected to this exact runtime-cost critique of classic CSS-in-JS. Tailwind offers component-scoped-feeling styling — via co-located utility classes in markup — with build-time, not runtime, CSS generation, genuinely addressing the same original motivation (avoiding global CSS collision, styles living near component logic) that CSS-in-JS was solving, without its real runtime cost. This is the actual, documented reason for the broader industry shift, not simply changing fashion.

Is CSS-in-JS "Dead"? An Honest, Precise Answer

No, not entirely. It's still genuinely used in real, existing production codebases — a real, ongoing migration-cost consideration for teams that adopted it early, not something to casually rip out. Newer, genuinely zero-runtime variants remain a real, legitimate option for teams that specifically want CSS-in-JS's own dynamic-styling ergonomics without its classic runtime cost. "Declining in new project adoption" is the precise, honest claim — not "nobody uses this anymore."

Existing CSS-in-JS isn't an automatic migration target
A team currently using classic (runtime) CSS-in-JS shouldn't treat "we must migrate away immediately" as an automatic conclusion just because the broader industry trend has shifted. A real, working, adequately-performing production application already built this way has a genuine migration cost — cssfw1-9's own decision-framework territory — that has to be weighed against the real but sometimes modest performance benefit of switching, not treated as an obviously correct move in every case.
The paradigm tour is complete
This closes the loop cssfw1-1's own roadmap opened — four genuinely different paradigms now covered in full. cssfw1-9 weighs all of them against real project needs.

Hands-On Exercises

Exercise 1

Explain what CSS-in-JS actually is and the real, genuine problems it solved when it became popular — why was this a legitimate, sophisticated approach at the time, not simply a mistake?

📄 View solution
Exercise 2

Explain the central, real technical reason for CSS-in-JS's own decline (the runtime-cost distinction), and explain specifically how this makes it structurally different from every other paradigm covered in this course.

📄 View solution
Exercise 3

Using this chapter's own honest "is CSS-in-JS dead?" section, explain the precise, accurate claim about its current status — and using the warn-box, explain why an existing production team shouldn't treat migration away from it as an automatic, obvious decision.

📄 View solution

Chapter 8 Quick Reference

  • CSS-in-JS — real CSS written inside JS/component files, generated and injected at runtime by a library
  • Genuinely solved real problems: enforced component-scoped styles, natural prop/state-driven dynamic styling
  • Central decline reason: runtime cost — the ONLY paradigm in this course doing real styling work in the browser at runtime, not ahead of time
  • Zero-runtime successors (vanilla-extract, newer Emotion configs) close this gap via build-time extraction
  • Tailwind's own rise is directly connected to this exact runtime-cost critique — same motivations, no runtime cost
  • Precise claim: declining in NEW project adoption, not extinct — real production use and real zero-runtime options remain
  • An existing CSS-in-JS codebase isn't an automatic migration target — real migration cost vs. often-modest performance gain
  • Next chapter: Choosing the Right Approach — A Decision Framework