Tech

Rethinking Reusable CSS

How working with Tailwind shifted my thinking from semantic component classes to utility-first CSS


From "Card" Classes to Utility-First Thinking

For a long time, I followed what felt like the "right" way to write CSS: create reusable classes and apply them across the app.

A common example was the classic .card class.

.card {
  border-radius: 12px;
  border: 1px solid #444;
  padding: 12px;
  background: #fff;
}

Whenever I needed a card, I would just reuse this class. Simple, clean, and DRY... or so I thought.

The Problem with Reusable Component Classes

Over time, cracks started to show. Not every "card" is the same.

On one page, I might want a lighter border, a little more padding, a transparent background, or a subtle box shadow. Now I'm stuck with a few options, and none of them sounds great.

  1. Keep adding properties to .card
    • This turns the class into a bloated, unpredictable abstraction.
  2. Add modifier classes like <div class="card light-card extended-card">
    • This creates juggling with naming conventions and modifier combinations
  3. Override styles locally (e.g. page-specific CSS)
    • This introduces hidden dependencies and makes styles harder to trace.
  4. Duplicate or redefine .card
    • This is an invite to trouble, because there're same-named classes with different stylings across pages. Unintended consequences occur easily.

Eventually, the codebase becomes fragile. Small changes ripple across unrelated pages, and styling becomes a guessing game.

This Approach Isn't Wrong

It's worth saying that this pattern isn't inherently bad.

In fact, defining reusable component classes like .card works really well for

  • design systems with strict consistency
  • marketing sites with stable, predictable layouts
  • projects where visual variation is limited.

In those cases, having a single source of styles for a component is actually a strength.

The problem starts when your UI needs to flex. When components begin to vary slightly across contexts, the abstraction starts to leak, and the simplicity breaks down.

The Shift in Thinking

A couple of years ago, after working with Tailwind CSS, my perspective changed.

Instead of thinking in terms of abstract components like "card," I started thinking in terms of what the element actually does.

Compare these two approaches:

Semantic CSS

<div class="card"></div>

Utility-First

<div class="flex px-2 py-3 border-gray-500 rounded-md"></div>

The difference is subtle but powerful.

With the utility approach, I don't need to jump into a CSS file to understand what's happening. The styling is visible right where it's used.

Why This Feels Better

  1. No hidden behavior.
    • A class like .card tells me nothing about its appearance without context.
    • Utility classes are explicit: - flex -> layout - px-2 py-3 -> padding in x and y directions for spacing - border-gray-500 -> border styles - reads almost like a sentence
  2. No unintended side effects
    • A class does exactly what it's meant for, leading to no unintended behaviors. For example, I don't have to worry about what other styles a px-2 class has
  3. Easier customization
    • I can tweak the utilities to get a different card like
    <div class="flex px-4 py-3 border-gray-300 shadow-sm"></div>
    
  4. Better scalability
    • As the project grows, utility-first styling avoids the cascade and specificity issues that often plague large css codebases.

But is Reusability Gone?

Not at all. Reusability still exists, it just shifts from semantic classes to patterns. If I find myself repeating the same utilities often, I extract components (in React) or define small utility groups when truly necessary. The key difference is that abstraction becomes intentional, not default.

Final Thoughts.

What started as a clean abstraction .card eventually became a source of complexity not because the idea was flawed, but because the use case evolved.

Moving toward a utility-first mindset made styling more:

  • predictable
  • readable
  • and maintainable

It's less about naming things, and more about describing them.


← All posts