My criticism of Tailwind CSS - lack of naming convention
Context: I’ve worked on multiple projects where Tailwind is used for styling components. Also, it should be obvious that this criticism is coming from a place of love. I absolutely like Tailwind CSS and want to see it become better.
The problem
Let’s say I’m building some UI (a React component) from a Figma design file or some HTML page. I need to inspect CSS and then write the equivalent Tailwind classes.
One of the most common tasks of building frontend is to format text (headings, paragraphs, etc). Here are the supposed text styles in CSS:
font-weight: 400;
font-size: 16px;
line-height: 24px;
color: #677489;
font-style: normal;
Below, the first one is CSS and then the corresponding Tailwind class. Let’s see if there’s a pattern in Tailwind classes:
font-weight: 400;
→font-[400]
orfont-normal
So we used just the first-word font
and skipped the second one -weight
__. Got it.
font-size: 16px;
→text-[16px]
ortext-base
shouldn’t it be size-
then? Where did text-
come from?
color: #677489;
→text-[#677489]
Didn’t we already use text
for font size?
line-height: 24px;
→leading-[24px]
orleading-6
hmmm…
font-style: normal;
→not-italic
Now, that’s just lazy writing
I could go on and find these inconsistencies everywhere in Tailwind. It makes it hard to remember classes and I constantly need to look up Tailwind docs. Things get even messier if I have to convert some complex CSS like gradients as I have no idea how to convert this to Tailwind class: background: linear-gradient(95.08deg, #FACEB8 2.49%, #E6AFCC 33.56%, #C8BEE5 64.63%, #ACD1F1 97.19%);
- It repeatedly wastes dev time.
- There’s an unnecessary learning curve (need for cramming).
- Not future-proof. Every aspiring front-end dev first needs to learn CSS and then the latest trending CSS framework lingo.
Proposed solution
What if there was a semantic way to come up with Tailwind classes so that there’s no need for devs to cram Tailwind classes anymore or keep that Tailwind docs tab open all the time. What if Tailwind classes could just use the same CSS properties:
font-weight: 400
→font-weight-[400]
orfont-weight-normal
font-size: 16px
→font-size-[400]
orfont-size-base
line-height: 24px
→line-height-[24px]
orline-height-6
color: #677489
→color-[#677489]
At this point, I could probably hear your mind screaming: we are back to writing CSS again! what’s the point of Tailwind then?
Tailwind shines in other areas. Try changing the background color when hovering over a button using the inline style, you’d feel the pain. Using Tailwind CSS, it’s just: hover:bg-[#f7f6f3]
. How would you disable the cursor when the button is in a disabled state w/o writing JS? with Tailwind, it’s just: disabled:cursor-not-allowed
. You also can’t use media queries in inline styles. Tailwind also helps in keeping a predefined design system: use could use font-size-base
instead of font-size-[400]
, color-primary
instead of color-[#677489]
.
My current workaround
While going through the Tailwind v3 release docs, I noticed Adam and his team added support for writing plain CSS (arbitrary properties) using bracket notation.
The basic idea is to put each CSS style inside a bracket i.e. [font-weight:400]
<div class="[font-weight:400] [font-size:16px] [line-height:24px] [color:#677489] [font-style:normal]">may your coffee kick in before the reality does</div>
It might look uglier to some but hey at least I don't have to check Tailwind classes anymore to understand what CSS styles are applied.
Benefits:
- Simple copy-pasting CSS from Figma, devtools style panel, etc.
- Easily understandable by others without the need to learn Tailwind classes / go through docs / hover over classes to see underlying CSS in VSCode.
- And, sometimes it’s even concise!
// using Tailwind classes
<button class="border-[4px] border-solid border-[#677489]">Sign up</button>
// using arbitrary properties
<button class="[border:4px_solid_#677489]">Sign up</button>
It’s a nice feature to solve the issues I mentioned but it’s still partially baked:
- If there’s a space it won’t work, for example:
[font-size: 16px]
would silently fail. To fix this you need to remove space, i.e.[font-size:16px]
. When I copy CSS from devtools or Figma there’s always a space between property and value and now I have to do an additional step of removing space. This could be handled by the parser instead. - If there’s a space in the CSS value then it needs to be replaced by an underscore first. So
[border:4px solid #677489]
won’t work but[border:4px_solid_#677489]
will. Again, an additional step is required from the dev side. It should be offloaded to the parser as well.
I liked the fact that if there’s a semi-colon ;
at the end (usually there is when copying CSS), it would still work, example: [font-weight:700;]
The underlying idea is to not go through additional steps and save dev time.
At this point, if you come up with the suggestion to use style
property (ex: style={{ fontWeight: "700" }}
) for CSS and Tailwind for complex CSS then I should remind you that I still need to do an additional step of converting plain CSS (font-weight: 700;
) to JS object ({ fontWeight: "700" }
)
Some other tools to save time
On a related note, here are some tools to save dev time when it comes to converting CSS to classes:
- Free web app to convert plain CSS to Tailwind classes: https://transform.tools/css-to-tailwind
- Paid Figma plugin to convert Figma design to Tailwind classes: https://www.firejet.io/ ($38/month)
- Paid Browser extension to convert any website CSS to Tailwind classes: https://usewindy.com/ (one-time payment of $59)