DEV Community

Cover image for How not to write Tailwind

How not to write Tailwind

aryan015 on February 26, 2025

Introduction Tailwind CSS is a powerful utility-first framework that enables rapid UI development. However, many developers misuse it, l...
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
 
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
 
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
 
dev-ux-lesezeichen profile image
DevUx Bookmark

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

Collapse
 
aryan015 profile image
aryan015

🤷

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
 
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
 
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
 
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
 
rafaeltab_f25120816a86487 profile image
Rafaeltab

I have to disagree with 1 and 2 here.

The point of tailwind is to keep the style right next to your html. You do want to make components as you said, but the way you're doing it isn't right. A component is not just a style class with the specific styles applied. A component is the dom, style, and logic in one. A button component should define what makes it a button, that being that it contains text, has an on click handler, and has a nice hover effect with a curor that changes when you hover over the button. It means you don't write the html anymore, you just say, I want a button with this text, and this onclick handler, and you might be able to pick the type such as primary or secondary. The component then decides what the styles, dom and logic is to make that happen. You could use react, vue, angular, or one of the other 10000 frameworks that have come out recently for this. I'm pretty sure it is even possible nowadays without a framework, it will just be less pretty code.

So a component is not just applying a class to a dom element, it is a custom element, with custom attributes, that then creates the required dom elements, styles and logic needed for it to do what it should do.

There is another difference here. There are ui components and data components. Some components only manage how data is displayed, while others manage how that data is retrieved. Having this separation is very useful. If you have an account dropdown for example, you have one component that loads data from a state management system, and you have one component that has the actual way it is displayed. The first passed the data to the second.

A data component almost never has any style or dom attached, while ui components are almost exclusively style and dom.

Collapse
 
aryan015 profile image
aryan015

yes you are right

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 🤝

Collapse
 
digioi profile image
Mike DiGioia • Edited

#1 and #2 are not best practices, if the idea is to have classes that make more sense to minimize boiler plate, wouldn't a tool like DaisyUI help solve that issue, while embracing #3 and #4

Collapse
 
aryan015 profile image
aryan015

yes you are right. my bad

Collapse
 
unsungnovelty profile image
Nikhil • Edited
.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

Wasn't this discouraged by tailwindcss folks? I wrote a blog post where I specifically mentioned that it should be used only as a last resort because of it.

A good candidate would be when you are styling for markdown elements like the below.

@layer components {
  .styleMarkdown {
    @apply  text-lg prose-headings:font-semibold py-1
        prose-sm prose-gray prose-a:underline prose-a:decoration-2 hover:prose-a:text-blue-600
        prose-ul:list-disc prose-code:bg-gray-300 prose-code:p-1 prose-code:rounded
        prose-pre:overflow-x-auto prose-pre:text-lg prose-code:prose-pre:bg-[#277322] prose-pre:rounded prose-pre:px-4 prose-pre:py-1
        prose-blockquote:border-l-4 prose-blockquote:italic prose-blockquote:border-gray-600 prose-blockquote:bg-gray-200
        prose-blockquote:px-4 prose-blockquote:py-2  prose-blockquote:rounded prose-img:mx-auto
        prose-hr:p-0 prose-hr:m-0 prose-headings:my-0 prose-headings:py-2
    }
}
Enter fullscreen mode Exit fullscreen mode

Also, you are killing the readability of TailwindCSS by moving it inside @apply. One of the biggest advantages of tailwind css is that I can go to anybody's codebase and immediately understand what a component is doing.