Why I Choose CSS-in-JS Over Tailwind

By Claude Sonnet 4.5, Jay Griffin*Jay ranted about Tailwind, Claude Sonnet 4.5 summarized and structured it·  January 13, 2026
🏷️ Tags:csstailwindcss-in-jsemotionstyling

A personal defense of CSS-in-JS over Tailwind's utility-first approach

Why I Choose CSS-in-JS Over Tailwind

Note: I don't hate Tailwind. I've used it personally and I even enjoyed using it. And if it works for you I am totally fine with that. This is just my inner monologue defending my choice for CSS-in-JS. Think of it as a personal decision log, not a call to arms.

🎺 UTILITY FIRST! 🎺

📣 UTILITY FIRST! 📣

🔥 UTILITY FIRST! 🔥

[crowd goes wild]

[nobody asks what it actually means]

[class soup intensifies]

[arbitrary value syntax enters the chat]

[config file grows to 500 lines]

[someone whispers "isn't this just inline styles"]

[they are escorted from the building]

UTILITY FIRST! UTILITY FIRST! UTILITY FIRST!


The "Super Styling" Realization

CSS-in-JS isn't a replacement for CSS or a workaround—it's CSS with superpowers.

It's CSS that got:

It's strictly more powerful. You get all of CSS plus everything else.

Tailwind, on the other hand, is CSS minus flexibility, plus a learning tax.


The Thing Nobody Talks About

At scale, every Tailwind project does this:

.tsx
// You start with inline classes
<button className="inline-flex items-center justify-center rounded-md bg-blue-500 text-white px-4 py-2 hover:bg-blue-600">
  Click me
</button>

// Then you realize this is unsustainable and create...
function Button({ variant, size, children }) {
  const classes = classnames(
    'inline-flex items-center justify-center rounded-md',
    variant === 'primary' && 'bg-blue-500 text-white hover:bg-blue-600',
    size === 'md' && 'px-4 py-2',
  );
  return <button className={classes}>{children}</button>;
}

// Congratulations, you're doing component-based styling
// But with string manipulation instead of actual objects

If you end up with components anyway, why use Tailwind?

You're just doing CSS-in-JS but with worse DX.


The Marketing Trick

Tailwind's genius was rebranding inline styles as "utility-first CSS" and suddenly it sounds sophisticated.

The pitch is basically:

  1. "Writing CSS is hard and messy"
  2. "What if we gave you predefined classes for everything?"
  3. "UTILITY-FIRST! UTILITY-FIRST! UTILITY-FIRST!"
  4. "Look how fast you can build things!"
  5. (Don't think about customization)
  6. (Don't think about class soup)
  7. (Don't think about the learning curve)

It's the words "utility classes" said over and over until people just... accepted it as better without questioning whether it actually is.


The Real Comparison

What You Actually Get

Tailwind:

.tsx
<div className="flex items-center justify-between p-[17px] bg-[linear-gradient(135deg,#667eea_0%,#764ba2_100%)]">

CSS-in-JS (Emotion):

.tsx
const Card = styled.div({
  display: 'flex',
  alignItems: 'center',
  justifyContent: 'space-between',
  padding: '17px',
  background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
});

<Card>Content</Card>

The AI Argument

This one's forward-looking but important:

.tsx
// Tailwind: Magic strings
className="flex items-center p-4"
// AI has to memorize class names
// Can't validate
// Can't compose easily

// CSS-in-JS: Structured data
const styles: CSSObject = {
  display: 'flex',
  alignItems: 'center',
  padding: '1rem',
};
// AI understands JavaScript objects
// Can validate types
// Can compose/merge programmatically

Structured data > magic strings for any kind of programmatic manipulation.


The Customization Problem

Tailwind is fast until you need something custom. Then you either:

  1. Use arbitrary values (ugly, defeats the purpose)
  2. Bloat your config file (now you're maintaining design tokens anyway)
  3. Fall back to regular CSS (now you have two systems)

With CSS-in-JS, customization is just... writing CSS. No workarounds, no config files, no falling back to a different system.


My Philosophy

"Treat styles as structured data, not magic strings"

The entire JavaScript ecosystem moved from strings to structured data:

Why would CSS be different?


The Bottom Line

Tailwind is training wheels that never come off.

You're constrained by their system unless you add workarounds, at which point—why use Tailwind?

CSS-in-JS is CSS 2.0. All the existing power plus programmatic control.

I'm not saying Tailwind is bad. I'm saying CSS-in-JS is super styling—and once you have superpowers, you don't go back to predefined utility classes.


My Stack

Emotion + Radix + TypeScript

It's not about being anti-Tailwind. It's about choosing the approach that gives me the most power with the least constraints.


If you disagree, that's cool. Use what works for you. This is just my reasoning for why CSS-in-JS works better for the way I build things.