Lob's website experience is not optimized for Internet Explorer.
Please choose another browser.

Engineering
January 16, 2023

Tailwind, one year later

by 
Walker Palecek

For those not familiar, Tailwind CSS is an open source CSS framework. I’d heard good things, but this might be the best testimonial I’ve ever seen: 

“Best practices” don’t actually work. I’ve written a few thousand words on why traditional “semantic class names” are the reason CSS is hard to maintain, but the truth is you’re never going to believe me until you actually try it. If you can suppress the urge to retch long enough to give it a chance, I really think you’ll wonder how you ever worked with CSS any other way. —Adam Wathan, Creator of Tailwind CSS

I couldn’t help but wonder, is Tailwind really all that? I know our Engineering team moved to Tailwind about a year ago so I decided to catch up with software engineers on our Dashboard & Growth team. I wanted to get an insider’s perspective on Tailwind and if it was still living up to the hype one year later.

What was the business context for using Tailwind? 

The team worked on replatforming Lob’s customer-facing dashboard from Angular into Vue; so we started two frontend projects from scratch: the component library, and the new dashboard.

Roughly what was the scope of the project?

The core team working on the frontend was 8 developers & 1 product manager.

We have our custom component library with ~40 components and our dashboard is an SPA with many many routes and sub-routes (hard to count, it keeps growing).

Why did you choose Tailwind?

There is is plenty of debate over CMS frameworks (for example, see Vanilla CSS vs Bootstrap vs Tailwind) The team considered alternatives such as Sass, styled-components, and BEM, in addition to more fully-featured UI component libraries like Material UI.

We ultimately decided against a more fully-featured UI component library so we would have more granular control and flexibility over our own UI components.

When the team was deciding which framework to use for the replatform of the dashboard, it was noted, “No matter what framework we choose, I recommend TailwindCSS as the utility CSS framework. I believe that the less layout CSS we have, the easier it is to maintain our CSS.”

The main benefit of Tailwind is that it reduces the need for style blocks and named classes that can easily get long & messy.

Tailwind provides utility classes. Here is an example:

Without Tailwind

<template>
  <div class=”box-with-blue-border”/>
</template>
<style>
  .box-with-blue-border {

      width: 40px;
      height: 40px;
      border: 1px solid blue;
  }
</style>

With Tailwind

<template>
  <div class=”w-10 h-10 border border-blue”/>
</template>

Another big draw of Tailwind is that it makes maintaining CSS and keeping styles consistent almost trivial. For example, you'll never end up with  5 different versions of almost the same class in different places in the code because the authors just didn't know the class already existed but just ever so slightly different (even when using something like SASS that allows you to reuse CSS).

It also takes away the mental load of having to come up with properly-descriptive class names. Names like 'inner-upper-container-blue' are difficult to interpret, maintain (what if you want to add another style to it?), and use/reuse (was that class called ‘container-blue’ or ‘blue-container’?).

While it’s primarily our Dashboard & Growth team that works with the front-end of Lob’s application, other teams and engineers do as well. The team felt like it would be the solution that allowed for a relatively small learning curve while still making it easy for other engineers to contribute maintainable, scalable code.

What were some of the early discoveries?

A criticism on Tailwind is that it can bloat your HTML/template with a whole bunch of classes, and some folks don't like that—but we found that the benefits outweigh this.

We did have some challenges with the changes from Tailwind v2 to v3, the plugins, and trying to make our external Tailwind plugin work with both the components library and the dashboard. We eventually sorted this out: our external Tailwind plugin holds the Tailwind configuration as a package (fonts, colors, sizes, etc), and this gets imported to both components and dashboard; this helps us maintain consistency across projects.

How long did it take the team to be comfortable using Tailwind?

Tailwind is easy to learn but requires knowledge of CSS—you need to know exactly what classes you want to use, then finding the Tailwind syntax for that is easy, as Tailwind has some fantastic and very easy-to-navigate docs. You can be comfortable with Tailwind within a week, then the more you use it, the less you need to look classes up in the docs as you remember the syntax.

If someone is brand new to the team, how long would it take them to be comfortable making changes?

Given pre-existing knowledge of CSS, I’d say about a day. Tailwind does not provide ready-made components like other libraries do (like Material or Bootstrap), so the developer needs to have enough knowledge of CSS to use it.

A helpful tool that I’d recommend is the Tailwind CSS IntelliSense extension. It shows a tooltip with the CSS code when hovering over classes in your code.

Do you have a component library? How does Tailwind fit into that?

We wrote and used our Vue component library that is made with Vue & Tailwind and demoed on Storybook. It is easy to read and consistent in code practices, with very little CSS clutter in the code files. 

How is the Tailwind support for Vue?

Tailwind is versatile and can be used with or without other libraries and frameworks. Vue & Tailwind is an excellent duo because they are both easy to learn and you can spin up code quickly.

If you could change one thing about Tailwind what would it be?

Tailwind has already improved greatly in version 3 by being able to eliminate unnecessary classes without an external dependency on purgeCSS, adding defaults that used to need plugins, enabled stackable modifiers, etc. That said, I can’t think of anything missing, as most of the things you’ll need are doable in some way—not always straightforward, but doable! 

Recently I was able to fix a gradient angle with a Tailwind plugin in the config, which we now use as `gradient-114` class and it saved us some big style blocks in writing the gradient styles of our Buttons.

Extra-artsy CSS with pseudo-classes can get tricky. The only cases where we may need to use a CSS style block in the code is when using pseudo-classes or selectors (like ::before/::after); these are quite confusing even in their simplest form and often need to be stacked, so we are using style blocks for them in some of our demanding components (i.e., custom radio buttons).

One year in, what are some of the lessons learned?

We learned that Tailwind removes/purges any unused classes on build. We noticed this happening for dynamic classes that were not part of the template. 

For example:
<template>
  <div :class=”`${dynamicClass}`”/>
</template>

<script setup>

import { computed } from 'vue'

const dynamicClass = computed(() => {

  return “text-blue-500’’;

})

</script>

Then the class “text-blue-500” must be safelisted in the tailwind.config.js file.

One may wonder where the classes went but there are ways around this, like allowlisting or declaring the class elsewhere—but it can take a first-time user a while to figure out.

Another learned lesson was that when using two projects (the component library gets imported to the dashboard), the main project will end up with two minified CSS files. The order in which they are being read by the project is important, as classes may be overwritten by this order.

 The order you apply classes in the code doesn't matter, what matters is the order they appear in the built CSS files, and that's why sometimes we had to use the !important CSS rule. 

Now when writing classes we prefer to use
`{booleanA ? 'someClass' : 'someOtherClass'}` to avoid the issue when possible (instead of assigning `someOtherClass`, and then `{booleanA: !someClass}` to overwrite it).

Looking back at your decision, did Tailwind meet expectations?

Absolutely, Tailwind is the best and a joy to work with. Fast to learn it, fast to type it. Fast to push.

Would you recommend using Tailwind for a similar project now?

I would never not use Tailwind in future projects if it was up to me!

There you have it. A pretty powerful testimonial—even if it doesn't reference vomit 😜.