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>
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;
}
<div class="btn">Button</div>
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>
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;
}
<div class="card">
<h2 class="card-title">Card Title</h2>
<p class="card-desc">This is a card description.</p>
</div>
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>
Better Approach: Use Tailwind’s theme.extend
Edit tailwind.config.js
:
module.exports = {
theme: {
extend: {
colors: {
brandPrimary: '#ff5733',
darkBg: '#121212',
},
spacing: {
'18': '4.5rem',
},
},
},
};
Then use it in HTML:
<div class="text-brandPrimary bg-darkBg p-18">
Custom Styled Box
</div>
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;
}
Better Approach: Use Tailwind’s Official Plugins
Install plugins:
npm install @tailwindcss/forms @tailwindcss/typography
Modify tailwind.config.js
:
module.exports = {
plugins: [require('@tailwindcss/forms'), require('@tailwindcss/typography')],
};
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)
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.
i completely agree 2 ur point sir thank you
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:
becomes
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:
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 thediv
does, because it's explicitly a button, which includes styling and accessibility features you'd otherwise have to emulate somehow.A better approach to
would be
tl;dr:
Every step you take to improve the Tailwind experience brings you closer to using HTML/CSS as it was intended.
Imho Tailwind main strength is layout declaration.
Sort example a vertical list with nice gap:
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.
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.
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!
sure i will check out ty
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
then what to use instead sir ?
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:
You can use BEM to keep your class name unique also
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?
ok i will reconsider ty
Using tailwind like that, why not just write native CSS?
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
Vanilla CSS covers 100% of my needs, and I can style it in my browser's dev tools.
🤷
@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.
yes you right. i will revamp. ty
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 ...
This is how I'd like to start using Tailwind.
@apply
is a game-changer.indeed 🤝