DEV Community

Discussion on: TailwindCSS: Adds complexity, does nothing.

rsa profile image
Ranieri Althoff

Now you have to go through each component and manually change "text-blue-500" to "text-red-500". And with 1000 edits comes 1000 oppertunities to introduce a bug.

Ah, if only there existed search and replace...

tanzimibthesam profile image
Tanzim Ibthesam

Use @apply and use same style everywhere. In react Vue we use components so we can just change style in one Component and it would work elsewhere.

nieuwepixels profile image
Nieuwe Pixels

Not the point though. The point of CSS ,and/or SCSS for that matter, is too make styling more structured. If you need to do mass search/replace that might be a first cue.

Naming it primary, secondary ect. would be a way to go instead.

yungifez profile image
Ebuka Ifezue

Lol I've been seeing hate articles with things that are non existent problems

And besides if you are using a js framework or in my case laravel components it's as easy as changing one file

redaalaoui profile image
Réda Housni Alaoui

The whole issue with the frontend community, in one comment. Well done.

davidhellmann profile image
David Hellmann

When you have a Button comp… Easy. Maybe variant:red is not a good approach. variant:primary

problem solved. works also for all other comps. Don’t see the problem here from the author.

robvirtuoso profile image
robvirtuoso • Edited on

if only all developers were careful enough to use search and replace responsibly

sir_kane profile image
Ahmadou Waly NDIAYE

The author was referring to the number of code changes.
With standard CC, you have to do the change in just one place.

alunr profile image
Alun Rowe

You assume you want to replace all instances of text-blue-500

ashleyjsheridan profile image
Ashley Sheridan

If you're relying on find/replace tools to make hundreds or thousands of edits to your codebase because of a change like this, it's still a problem. Everyone has seen (or caused) a scenario where a find/replace has gone wrong and replaced the wrong thing by accident, e.g. replacing "Arial" with "ArialBold", but accidentally creating instances of "ArialBoldBold" because your find-fu was off.

However, if the code was following DRY principles, there would be very few instances that needed to be changed, so would be far more likely to be handled better.

raydot profile image

@Ranieri Althoff, if you have never introduced an error via search-and-replace I salute you for your charmed life as a developer!

ztom132 profile image

If only this was possible and such an easy change, you can't replace every instance of this in your app, what if it applies only to buttons/etc.

mariocalin profile image

We do we need constant values if we have search and replace...

imedacf profile image

Then don’t use functions at all

rubinelezi profile image
Rubin Elezi

Search and replace does not work all the time, as sometime you have to apply logic to it. Maybe you want to update only 763 elements.

rsa profile image
Ranieri Althoff

In that case, you will still need to go one by one changing the class if you just put "button" in all of them.

Thread Thread
brianboyko profile image
Brian Boyko Author

You shouldn't. If the class is .button, and the .button class is only defined once, then one change to the .button class definition in your css should apply to all items that have the .button class.

I should have been clearer in my example by using something like ".branded-button" but you do see how you don't have to go in one by one, right? Because you're not changing what the class is named, only what the class does.

Thread Thread
milan090 profile image

You often create a component for these scenarios, making different button components and reusing them. This pattern follows DRY too and also gives you the tooling and productivity of tailwind.

cjpartridgeb profile image
Chris Partridge

Or just create a custom color palette in your Tailwind config called 'brand', set your colors and be done with it. If brand colors change, update the color palette - easy.

geewhizbang profile image
Geoffrey Swenson

A properly designed stylesheet tags an outer element with whatever the thing is. You then can assemble the object, and only light markup is needed for child elements because you can reach in with the stylesheet and control them. I had a job interview where they had "code standards" for doing css where you weren't allowed to nest tags to control them. Everything had to be top-level. Idiotic.

When you are writing code with frameworks, it's easy to use the framework to be absolutely consistent about how the children are constructed, so the markup can be very minimal. It makes it easy to read when the css tags are only used when they actually control some behavior, and they read semantically rather than as named inline styles.

delanyobott profile image
delanyo {Yokoyama} agbenyo • Edited on

Color is not a brand, after all. And that could be a "hack". You don't try to win.

kamel3d profile image
Kamel Labiad

He seems to blame the tool rather than using a better methodology for writing a better style

brianboyko profile image
Brian Boyko Author

Right, but branding is more than just color palettes. It's also - do we want the corners to be more round or less round on buttons. What if we want to have switch toggles instead of checkbox toggles? What if we want a specific page to look like a specific brand that isn't our main brand?

(This happened with a client of ours which sold Louis-Vitton gear -- Louis-Vitton wouldn't allow them to sell LV stuff on the client's page unless the pages that they landed on were branded with Luis-Vitton's color scheme).

Thread Thread
cjpartridgeb profile image
Chris Partridge

Right, and Tailwind offers plenty of flexibility to manage these things via your config if required. It's not just a static set of a utility classes that cannot be altered without digging into the source - override the default border radius settings, or create your own presets for your brand if need be.

The exact use case in your article and comment (branded button) is mentioned in their documentation somewhere (I distinctly recall reading it), and I'm sure they suggest creating your own branded button class using @apply. If your branded button border radius requirements change, update the class, if the new border radius is outside the presets, then extend the config and then update the class.

If a specific client demands you brand their pages, then add a color palette for their brand, and make sure those components switch out brand for client-brand where required? Tailwind certainly doesn't stop you from using colors outside their default palette - I've only ever used the provided colors for non-brand accenting (e.g. greens for success, reds for errors, etc) and the grays for text/borders.

In regards to moving to switch toggles from checkbox toggles, you're likely going to adjust the layout of the component somewhat, or perhaps add an additional container element ensure things are aligned correctly - I've encountered this exact type of scenario many times over the years - more often than not, it's more than just a few lines of CSS.

And if you're building a modern application, you'll likely have a checkbox component or at least a rudimentary template/partial to stay DRY - which will prevent the need to update every occurrence of that particular component across your application - again, something which I believe they touch on in their documentation.

To be frank, I wasn't a fan of Tailwind at first, and I certainly don't think it's the "be-all and end-all" solution - but after using it on a few projects I've come to love what it offers out of the box (especially the font, text sizing defaults, colors for accenting, gray set, grid, gradients, screen breakpoints, space-between, etc) with the ability to extend/override anything I desire if the case arises.

It's really allowed me (as a full stack developer building business applications) to start flowing without having to worry about any of aforementioned when I just want to get something clean, consistent and functional on the screen.

With all that being said, if you're creating basic web sites, landing pages, marketing pages - or complex applications without a component framework - Tailwind probably isn't the solution you want.

Thread Thread
brianboyko profile image
Brian Boyko Author

The problem is that the minute you start using @apply and using semantic classes again, you're moving outside of Tailwind's "utility classes" paradigm.

Now - while I could argue that "you might as well just write out the CSS" there is some value to alternative syntaxes. There's all sorts of tools for transpiling non-standard code into standard code. Typescript -> Javascript, Coffescript -> Javascript, ES2015+ -> Babel -> ES5, Sass -> CSS, SCSS -> CSS, LESS -> CSS, Knex -> SQL...

It would be an interesting -- and I think worthwhile! -- project that would use only @apply in CSS files and then transpile them (maybe with SCSS) into the appropriate CSS around the same time you're transpiling all those "$" prefixed variables, Sass functions, and "&" notation. If you want to have a tool that is designed to make @apply px-5 shorthand for padding-left: 5rem;
padding-right: 5rem;
then that would be an interesting tool that wouldn't break semantic structure.

Thread Thread
cjpartridgeb profile image
Chris Partridge

I've had the same thought - and it's essentially what I've been playing around with on a Svelte project with Tailwind's JIT mode. All the component markup, script and style tags are self contained in their own .svelte files - using @apply in classes within the style tag.

Certainly makes the mark up a lot easier to reason with when you have a lot of nested elements and many utility classes applied - I won't argue that fact.

The only issues I can see are:

1) Each components generated CSS classes are included in their own style tag within the head element, so I'm not sure what sort of performance issues this might cause if you have a lot of components.

2) Any class used with @apply within the svelte components, gets marked as "used" by Tailwind and ends up being compiled into the stylesheet loaded on the page. So if you don't use those utility classes in the mark up (and only in classes), they are essentially dead weight.

I'm sure neither issue would be difficult to resolve - either way, it's interesting none the less!

Thread Thread
mc72 profile image
Mike Ciccone

See, and this is the problem with writing a very opinionated article without understanding it. Tailwind is trying to get you away from using the @apply method. They have mention that in multiple tweets, articles, and videos.

Instead of @apply bg-blue-500 for your brand you can easily set a color theme of "brand" in your config then use your theme in the css. ie:

.button {
background-color: theme('bg-brand-500');
font-family: theme('fontFamily.brand');
///and any other variable you have set in your tailwind config.

then you just change your tailwind.config when you need to and you are done. Same as using a sass variable etc. It's not that hard and completely follows a dry principle.

pgollucci profile image
Philip M. Gollucci

That's not true, you can use 'primary', 'secondary', etc.

brianboyko profile image
Brian Boyko Author

But that's just it.

Search and replace will only search and replace based on text strings. Which is great if the only place you use "text-blue-500" is in components you want to change.

That's the thing about utility classes - by definition, they're the same name everywhere you use them. So if you wanted to change "text-blue-500" to "text-red-500" in buttons -- and only buttons -- you'd have to find, and then manually look to see if it's a button before you replace it.

On the other hand, if you have a .button class, or even better, a .branded-button class, you can just change it in one place.

Find and Replace might be useful for changing variable names that are already fairly unique, such as from "my-button" to "branded-button" but it's not useful if you're trying to change, say, only some instances of "float-left" to "float-right".

jamesthomson profile image
James Thomson

On the other hand, if you have a .button class, or even better, a .branded-button class, you can just change it in one place.

But this is exactly how you should be using Tailwind anyway. If you are applying utility classes all over your html to make your buttons then this is akin to using inline styling. The power of tailwind is that you have an entire set of utility classes that allow you to make small tweaks on the fly because your designer wanted this specific button to have juuuuust a bit more margin-top and be fullwidth at certain resolutions, but you can also continue writing CSS as normal.

I see Tailwind as a utility. It's not there to replace CSS, but compliment your workflow so you can get on with building components.

Anyway, judging by your article and your replies in the comments you've made up your mind about Tailwind and that's ok, but there are many developers that are in favour of it, myself included. Best of luck!

Thread Thread
brianboyko profile image
Brian Boyko Author

I'm sure that you could use Tailwind that way, but at that point - why not just use small tweaks in inline styles instead of using Tailwind's classes? Inline styles also have the advantage of being higher CSS priority than class definitions, so you get exactly what you want right away.

But then again, the problem with "if you use it this way" arguments is that they're different from "if you use it as intended." You can see from the Tailwind's own documentation that the intended purpose is to replace CSS.

I'm not saying that utility classes aren't useful. I'm just saying that they shouldn't be used for everything. And they certainly shouldn't need all the tooling overhead that comes with tailwind.

Thread Thread
tofraley profile image
Taylor Fraley

I don't know why you keep saying this is not how Tailwind is intended to be used. The page you linked to is titled "Utility First". I infer that to mean the expectation is you start with utilities, and move to something else if you need it. Practically every word on that page seems to back up that inference.

Further down the page is a section titled "Why not just use inline styles?" which explains what they see as the advantages of utility classes over inline styles. You didn't even acknowledge their reasoning in your article.

The section after that one is "Maintainability concerns". This is where they expressly state that using apply to group styles together is, actually, using it "as intended".

Again, it seems clear to me Tailwind's intention is you would build styles using utility classes first. After some point, they completely expect you to group at least some of those utility classes into a "bigger" class. You seem to think this grouping completely negates the benefits of using utility classes, and that you might as well write it in CSS.

The documentation page that discusses this in particular is Extracting Components.

I'm always wary when somebody says a newer syntax is "hard to read". It's definitely possible to write code that is hard to read. But how can you say it's hard to read when you've spent years training your brain to parse some other syntax. Readibility is subjective with things like this.

For example, I found the example line in your article pretty easy to read. The purpose of md:h-32 and lg:h-64 are actually more obvious to me than the media queries. But I do agree the long horizontal line harder to read. But you don't have to do it that way.

I like your analogy of using single letter variables. But I don't think it's the same thing. These are just short forms of CSS properties. They are clear and documented.

I'm not sold on Tailwind myself. But if your conclusion is that it "provides no value", I don't think you argued it that well.

Thread Thread
brianboyko profile image
Brian Boyko Author

I don't know why you keep saying this is not how Tailwind is intended to be used. The page you linked to is titled "Utility First". I infer that to mean the expectation is you start with utilities, and move to something else if you need it.

Eh... If that is your interpretation of Utility First, then I can't fault it.

It wasn't mine, for a number of reasons, but you may have caught me out on an assumption I didn't know I was making.

See, I thought that "Utility First" was referring to a coding philosophy, much like the philsophy of "Mobile First" -- you code for the mobile site first because the mobile site will always work on the full web-page, but not necessarily vice versa.

Mostly, though, the reason why I don't think your interpretation is correct (Start with utility classes, then move away from them) is because almost every example on Tailwind's site is about how you can convert from semantic classes and CSS/SCSS to Tailwind Utility classes. If anything, Tailwind seems to suggest that CSS is a pain point that needs to be resolved and that utility classes are the solution.

I agree that Tailwind might have use with rapid prototyping, but there's no real instruction on how to move from rapid prototyping to final product - You write Tailwind, you distribute Tailwind.

I'm always wary when somebody says a newer syntax is "hard to read". It's definitely possible to write code that is hard to read. But how can you say it's hard to read when you've spent years training your brain to parse some other syntax. Readibility is subjective with things like this.

I remember a similar argument from the author of Clojure about how Clojure (and other Lisp-like languages) were "hard to read." He said: "I don't know how to read German, that doesn't mean that things written in German are hard to read."

But we can admit to ourselves that it is harder to learn certain languages than others, especially for an English speaker. And we can ask questions: Does this have a similar grammatical syntax? Does the language belong to the same family, does it have cognates and loan-words? Does it use the same sounds and tones? Is the alphabet the same?

In the case of programming languages, we can ask similar questions:

  • Does the syntax provide valuable information about what it does? ('height' vs. 'h-', for ex.)
  • Is the syntax internally consistant (Not actually a problem with Tailwind, though PHP suffers from this.)
  • Does it introduce concepts not familiar to other languages? (C's lack of memory safety, Rust's 'ownership', Lisp's Polish Notation, and if you're coming from a dynamically typed language like JS/Python, static typing of TS/C#/Java/C++?)
  • Is it relatively clear to follow the structure of a program written in this language? (CSS is horribly bad at this, as priority order rules can get complex, latter styles overwrite former ones, and of course, there's the !important flag.)

In this case, my criticism of Tailwind being "hard to read" deals primarily on the fact that the syntax is not expressive, and indeeds, chooses terseness over expressiveness. Back in the days of limited memory, sometimes a terse command was better than a long one, we still use "cd" for change-directory and "ls" for "list" in most Unix shells, but no such memory problems were at play here.

It's also hard to read because it's embedded inside HTML, listed horizontally, rather than vertically. Now I'm not saying that it would be as hard to read as if we did styles in PDoublePrime but compared to the default of regular CSS, it makes it hard to read. Additionally, since you're no longer adding your own semantic class names to your HTML, it can be hard to tell by looking at the source exactly what element in the HTML code you're actually looking at when you debug it.

patricknelson profile image
Patrick Nelson • Edited on

Re: @tofraley

… because your designer wanted this specific button to have juuuuust a bit more margin-top and be fullwidth at certain resolutions…

At the risk of taking sides (trying not to as I don’t understand TailwindCSS enough), I will say this: Usually when I encounter situations like this, I’ll bring it up to the designer. When that happens, at least in our case, it’s usually a misunderstanding (but not always). For example:

  1. They have an outdated set of components in their PSD’s, or just out of sync, etc.
  2. They actually intended for us to change this site wide (and not just this one button)
  3. In some rare circumstances they really did this as a one off (and if that’s the case, it’s good to have that clarity so we can built it that way with intent).

Only pointing this out since, on the development side, all too often I’ve found developers simply matching the comps precisely without first ensuring that the change was intentional and (in this case, accidentally) creating one offs that ultimately weren’t really intended. 😊