The CSS-in-JS Hangover: Moving Past Runtime Styling

I spent three days last month debugging a flash of unstyled content on a client’s staging environment. Three days. The culprit? A legacy styled-components setup fighting a losing battle against React Server Components. It’s exhausting. We are still dealing with hydration mismatches from a styling pattern we probably should have retired a few years ago.

Look, I get why we all jumped on the CSS-in-JS train. Writing actual CSS right inside the React component felt like magic back in 2019. You didn’t have to worry about class name collisions. You just passed a prop and the button turned red. It was clean. It made sense mentally.

But the performance cost was massive. We were shipping megabytes of JavaScript just to parse strings into CSS at runtime.

The Runtime Trap

React programming code - Using React in Visual Studio Code
React programming code – Using React in Visual Studio Code

I remember running a profiling session on our main dashboard running Next.js 15.1 late last year. The JavaScript execution time was entirely dominated by style injection. And every time a user clicked a tab, the browser had to recalculate styles, generate new hashes, and inject them into the document head.

We eventually ripped out Emotion entirely. We dropped our memory usage on the Node containers by 42%. That’s not a rounding error — it’s a structural flaw in how we were building web apps.

The React ecosystem has moved aggressively toward Server Components. That architecture fundamentally breaks the context providers that runtime CSS-in-JS libraries rely on to collect and inject styles during SSR. You can hack around it, but you’re fighting the framework.

The Zero-Runtime Mirage

Then came the zero-runtime wave. Tools like vanilla-extract and Panda CSS promised salvation. Keep the component-scoped syntax, lose the client-side overhead. I migrated a medium-sized project to Panda last spring. It worked.

React programming code - Using React in Visual Studio Code
React programming code – Using React in Visual Studio Code

Mostly.

Here’s the gotcha nobody warns you about with zero-runtime extraction: your build times take a beating. On my M3 Max MacBook, our Vite build went from 4.2 seconds to over 18 seconds after adding the extraction step. The bundler has to traverse your AST, evaluate your styling code in a mini-runtime, extract the static strings, and generate CSS modules. When you have 800 components, that parsing isn’t free. You basically trade client performance for developer experience misery.

I found myself waiting on HMR updates that used to be instant. It broke my flow completely.

CSS code on screen - Add a Shared CSS Code Snippet
CSS code on screen – Add a Shared CSS Code Snippet

Where We Actually Are Now

The conversation around styling has shifted entirely because the problem we were trying to solve—component encapsulation—got solved better by utility classes. Designers don’t care about our styled-components props. They care about Figma auto-layouts behaving predictably in the browser. We’re finally seeing a wave of visual tooling that outputs actual, maintainable React code with standard Tailwind utility classes. No weird abstraction layers. Just standard flexbox and grid layouts that a browser can render without a 50kb JavaScript parser.

I tested one of these newer code-generation pipelines last Tuesday. I dropped a complex nested grid layout from a design file, and it spit out idiomatic Next.js code. Clean divs. Standard Tailwind classes. I didn’t have to map a single styled prop. It just worked.

If you’re starting a new React project today, avoid runtime CSS-in-JS. Just don’t do it. Use Tailwind. Use CSS modules if you hate utility classes. But stop shipping style parsers to users on 3G connections. The era of CSS-in-JS was a necessary stepping stone, but I’m glad we’re finally moving past it.

Your email address will not be published. Required fields are marked *

Zeen Social Icons