DEV Community

Cover image for How not to write Tailwind
aryan015
aryan015

Posted on

How not to write Tailwind

Introduction

Tailwind CSS is a powerful utility-first framework that enables rapid UI development. However, many developers misuse it, leading to bloated HTML, poor maintainability, and unnecessary complexity. In this article, we'll explore the most common mistakes developers make when using Tailwind and how to avoid them.

1. Writing Messy & Bloated HTML

Bad Example:

<div class="bg-red-500 text-white p-4 m-2 rounded-lg shadow-lg flex justify-center items-center text-lg font-bold border border-red-700">
    Button
</div>
Enter fullscreen mode Exit fullscreen mode

Better Approach: Use @apply in CSS

.btn {
    @apply bg-red-500 text-white p-4 rounded-lg shadow-lg text-lg font-bold border border-red-700;
}
Enter fullscreen mode Exit fullscreen mode
<div class="btn">Button</div>
Enter fullscreen mode Exit fullscreen mode

Why?

  • Keeps HTML cleaner and more readable.
  • Makes styles reusable across multiple components.

2. Overusing Utility Classes Instead of Components

Bad Example:

<div class="w-64 h-40 bg-gray-200 p-4 rounded-lg shadow-lg">
    <h2 class="text-lg font-bold">Card Title</h2>
    <p class="text-gray-600">This is a card description.</p>
</div>
Enter fullscreen mode Exit fullscreen mode

Better Approach: Extract Components

.card {
    @apply w-64 h-40 bg-gray-200 p-4 rounded-lg shadow-lg;
}
.card-title {
    @apply text-lg font-bold;
}
.card-desc {
    @apply text-gray-600;
}
Enter fullscreen mode Exit fullscreen mode
<div class="card">
    <h2 class="card-title">Card Title</h2>
    <p class="card-desc">This is a card description.</p>
</div>
Enter fullscreen mode Exit fullscreen mode

Why?

  • Reduces duplication.
  • Makes modifications easier.

3. Not Using Tailwind’s Config for Customization

Bad Example (Hardcoded Values in Classes):

<div class="text-[#ff5733] bg-[#121212] p-[18px]">
    Custom Styled Box
</div>
Enter fullscreen mode Exit fullscreen mode

Better Approach: Use Tailwind’s theme.extend

Edit tailwind.config.js:

module.exports = {
  theme: {
    extend: {
      colors: {
        brandPrimary: '#ff5733',
        darkBg: '#121212',
      },
      spacing: {
        '18': '4.5rem',
      },
    },
  },
};
Enter fullscreen mode Exit fullscreen mode

Then use it in HTML:

<div class="text-brandPrimary bg-darkBg p-18">
    Custom Styled Box
</div>
Enter fullscreen mode Exit fullscreen mode

Why?

  • Improves maintainability and consistency.
  • Allows easy theme updates.

4. Ignoring Tailwind Plugins for Reusability

Bad Example (Writing Custom CSS Instead of Using Plugins):

.btn {
    background-color: #ff5733;
    padding: 10px 20px;
    border-radius: 5px;
}
Enter fullscreen mode Exit fullscreen mode

Better Approach: Use Tailwind’s Official Plugins

Install plugins:

npm install @tailwindcss/forms @tailwindcss/typography
Enter fullscreen mode Exit fullscreen mode

Modify tailwind.config.js:

module.exports = {
  plugins: [require('@tailwindcss/forms'), require('@tailwindcss/typography')],
};
Enter fullscreen mode Exit fullscreen mode

Why?

  • Reduces custom CSS.
  • Uses optimized, pre-built styles.

Conclusion

By avoiding these common mistakes, you can write cleaner, more maintainable Tailwind CSS code. Focus on:
✅ Keeping HTML clean using @apply.
✅ Extracting reusable components.
✅ Leveraging Tailwind’s configuration.
✅ Using Tailwind’s built-in plugins.

Writing Tailwind correctly ensures a scalable and efficient project. Happy coding! 🚀

Top comments (25)

Collapse
 
alohci profile image
Nicholas Stimpson

Tailwind is a re-invention of inline styling through class names. The main plus-points that I read mostly for using Tailwind are that 1. it places your styling in the HTML so you don't have to keep switching source files or keep track of what styles apply to what elements; and 2. that you don't have to spend time and effort having to think up class names for your components. The principles that you advocate here, particularly the first two points which I think are in themselves sound, undermine both those supposed benefits.

Collapse
 
aryan015 profile image
aryan015

i completely agree 2 ur point sir thank you

Collapse
 
moopet profile image
Ben Sinclair

I partly agree with you.

Using classes and @apply makes things a lot better. However, it's explicitly discouraged by Tailwind's author.

An improvement would be to use abstracted variable names instead of explicit colours:

.btn {
    @apply bg-red-500 text-white p-4 rounded-lg shadow-lg text-lg font-bold border border-red-700;
}
Enter fullscreen mode Exit fullscreen mode

becomes

.btn {
    @apply bg-primary-control-color text-body-text-color (etc.)...;
}
Enter fullscreen mode Exit fullscreen mode

at which point you may as well use regular CSS variables, because (1) they're a common standard, and (2) they eliminate a build step/point of failure in Tailwind:

button {
  background-color: var(--primary-control-color);
}
Enter fullscreen mode Exit fullscreen mode

And of course, Tailwind is one of the Great Enablers of non-semantic HTML, which is effectively just noise. All the examples use div for pretty much everything, leading inexperienced programmers (and LLMs) to think that's how you're supposed to do the web.

button doesn't need a class .btn the same way the div does, because it's explicitly a button, which includes styling and accessibility features you'd otherwise have to emulate somehow.

A better approach to

<div class="btn">Button</div>
Enter fullscreen mode Exit fullscreen mode

would be

<button value="value">Button</button>
Enter fullscreen mode Exit fullscreen mode

tl;dr:
Every step you take to improve the Tailwind experience brings you closer to using HTML/CSS as it was intended.

Collapse
 
pengeszikra profile image
Peter Vivo

Imho Tailwind main strength is layout declaration.
Sort example a vertical list with nice gap:

<section class="grid gap-4">
  <p>Alfa</p>
  <p>Beta</p>
  <p>Omega</p>
</section>
Enter fullscreen mode Exit fullscreen mode

Intensive tailwind example:
dev.to/pengeszikra/javascript-grea...

responsive markdown editor HTML raw code

A good reason I prefered a much readable vertical Tailwind class declaration because this is easy to read how behaviour this element on a different responsive situation. If I just use a class name then I did not read my view element, just when I go to the related CSS, where every one can use a more complex solution thx for the CSS capability to make a real crazy CSS selectors on definition which is also affect the page computing speed.

     <textarea class="
        opacity-90
        resize
        lg:relative
        min-h-[1rem]
        min-w-[100%]
        bg-zinc-800
        text-zinc-400
        focus:outline-none
        p-8
        my-0
        font-mono
        placeholder-zinc-600"
        placeholder=" - - - m a r k e r (c) - - - "
        spellcheck="false"
      ></textarea>
Enter fullscreen mode Exit fullscreen mode

But if take look my program Tailwind don't cover whole CSS. For example have great gap on CSS 3D, which I used intensive on the card game.

Collapse
 
hardikgohilhlr profile image
Hardik Gohil

Tailwind CSS makes styling so much faster, but remembering all the utility classes can be tricky.

That's why I built a Tailwind Cheatsheet for quick reference → cs.hardikgohilhlr.tech

Check it out and let me know if it helps!

Collapse
 
aryan015 profile image
aryan015

sure i will check out ty

Collapse
 
aloisseckar profile image
Alois Sečkár

My experience is rather oposite - I will try to avoid @apply more and more - dev.to/aloisseckar/i-was-using-tai...

Point 3 is a good one though

Collapse
 
aryan015 profile image
aryan015

then what to use instead sir ?

Collapse
 
aloisseckar profile image
Alois Sečkár

I believe Tailwind should primary be used as designed - to combine its prepaired classes inline in "class" attributes of HTML tags

To avoid situations from your example, you should:

  • divide classes between more elements to keep code readable
  • if not possible, at least seal it in a separate single reusable component
  • use component library
Thread Thread
 
aminmahjub profile image
Mmmad Amin Mahjub Asl • Edited

You can use BEM to keep your class name unique also

Collapse
 
blowsie profile image
Sam Blowes

You should really revisit point 1 , it's strongly discouraged and adds performance overhead. These days we can help the maintainability of the class names using prettier-plugin-tailwindcss. And even tools like tailwind variants. Also tailwind 4 is out, why not use that in this article?

Collapse
 
aryan015 profile image
aryan015

ok i will reconsider ty

Collapse
 
dev-ux-lesezeichen profile image
DevUx Bookmark

Using tailwind like that, why not just write native CSS?

Collapse
 
aloisseckar profile image
Alois Sečkár

Because you would have to re-invent the wheel in every single project again and again. Tailwind suits 99% of needs. And it is predictable.

And if you think it is too heavy while you only use fraction of its classes, there are Open Props

Collapse
 
dev-ux-lesezeichen profile image
DevUx Bookmark

Vanilla CSS covers 100% of my needs, and I can style it in my browser's dev tools.

Collapse
 
aryan015 profile image
aryan015

🤷

Collapse
 
amitind profile image
Amit Yadav

@apply should be ignored,

Maybe make frequently used elements as components,

And those components can have different variations.

Also using variables like shadcn does it will be easy to update theme when needed.

Collapse
 
aryan015 profile image
aryan015

yes you right. i will revamp. ty

Collapse
 
himanshu_code profile image
Himanshu Sorathiya

Although you're using v3, ( tailwinds v4 released already I guess one month ago, and with that you don't need to put extras in configuration file, you can put that in @theme layer in css file ),

I prefer to use @apply everywhere in my code cause I don't like to read those classnames covering my 2 3 lines and also don't give any contextual information of what that part of html is doing, I know it's totally opposite of tailwinds idea of utility first via using more @apply. And as far as I know it just increases build time, but in production it won't cause any delays so I think I'm good to go via using BEM classnames and using @apply everywhere with few benefits like no clutter html, getting contextual info, resuability in common things like inputs, btns, card ...

Collapse
 
fstrube profile image
Franklin Strube

This is how I'd like to start using Tailwind. @apply is a game-changer.

Collapse
 
aryan015 profile image
aryan015

indeed 🤝