cd /news/developer-tools/real-world-tailwind-css-controlling-… · home topics developer-tools article
[ARTICLE · art-35538] src=dev.to ↗ pub= topic=developer-tools verified=true sentiment=· neutral

Real World Tailwind CSS: Controlling the Special Cases (Part 2/2)

A developer discusses strategies for managing special cases in Tailwind CSS, including avoiding prop explosion by isolating one-off designs in separate pages and creating campaign-specific components as a middle ground. The goal is to keep shared components focused and maintainable.

read2 min views1 publishedJun 21, 2026

So in the last article, we have discussed the best practices for using Tailwind CSS4 in the real world - which is,

In this way we "hide" the long utility class strings from rest of the codebase.

What happens when marketing launches a new campaign and needs a gradient CTA button that deviates from the core design system??

The obvious choice might be to do something like this:

const variants = {
  primary: "...",
  secondary: "...",
  // The new marketing variant
  "ai-campaign": "bg-gradient-to-r from-emerald-500 to-teal-500 animate-pulse text-lg px-8 py-4" 
};

This looks clean today. But in a few years, it might grow to

<Button
  variant="primary"
  isMarketing
  isAnimated
  hasGlowEffect
  showConfetti
  campaignTheme="black-friday-2024"
  seasonalBadge="sale"
  size="xl"
/>

Now it's bloated again... this is called prop explosion.

Sometimes a design is so specific that it's hard to imagine anyone using it again. So, just make the page live in a separate directory and use utility classes directory

////  Inside @/app/marketing/campaign/page.tsx ////
...
export default function CampaignPage() {
  return (
    <div>
      <h1>The Next Generation of AI</h1>

      {/* Custom, one-off visual classes are localized entirely to this page */}
      <Button
        className={cn("bg-indigo-600 text-white px-4 py-2", className)} >
        Get Early Access
      </Button>
    </div>
  );
}

Once the campaign ends, just delete the page. The component is left untouched.

If there are only a handful of visual styles and they genuinely represent something the business uses repeatedly, I'd probably just add another variant.

<Button variant="primary" />
<Button variant="secondary" />
<Button variant="cta" />
<Button variant="voucher" />

The props felt easy enough to understand, and it keeps the page code nice and clean. In a smaller codebase, maintaining a few extra variants would not be a big deal.

There's also a middle ground. If I find myself copying the same styling around a campaign or a particular section of the application, I'd probably start wondering whether it's worth creating something like a .

function CampaignButton(props) {
  return (
    <Button
      className={cn("bg-gradient-to-r from-emerald-500 to-teal-500 animate-pulse", 
      className
      )}
      {...props}
    />
  );
}

function CampaignButton({ className, ...props }) {
  return (
    <Button
      className={cn(
        "bg-gradient-to-r ...",
        className
      )}
      {...props}
    />
  );
}

// Base component
<Button>
  Testimonials
</Button>

// Campaign-specific component
<CampaignButton>
  Get Early Access
</CampaignButton>

That way the shared Button stays focused on being a button, while the campaign gets its own reusable abstraction. It feels like a reasonable compromise when you're not quite ready to promote something into the design system, but you don't want duplicated styling everywhere either.

The goal is:

Keep shared components focused, understandable, and maintainable.

Do you agree with the tradeoffs? What are your tips for writing even tidier and more maintainable components? Please share your experience ~ :)

── more in #developer-tools 4 stories · sorted by recency
── more on @tailwind css 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/real-world-tailwind-…] indexed:0 read:2min 2026-06-21 ·