FlyingWithTailwind

When I decided that my personal site needed a revamp, I did what every developer does and searched for the hottest new technologies to play with. After a bit of research, one of the things I chose was Tailwind CSS.

I've now built several projects with Tailwind, and we use Tailwind at my new job, so I feel like I've gotten pretty good with it. This post is based on a talk I gave to the Frontend guild at Deliveroo just before leaving. Hopefully it gives you a good idea of what Tailwind is and how to use it.

What is Tailwind?

First, let's talk about what it isn't. Tailwind isn't Bootstrap and it's not a design system like Material UI or Chaka. Frameworks and Design Systems like these can be great to get started with, but further down the line it can take more effort to customise them and your markup and CSS selectors must be a certain structure.

I've spoken to people who are used to dropping in some components and getting, for example, a tooltip, an accordion, or a carousel. Tailwind doesn't work like that.

Tailwind is an atomic CSS framework. This means it provides small utility classes that usually only do one thing. You then combine these classes on an element to build up your styling.

The Basics

Most Tailwind classes do one thing. w-1/2 is width: 50%;

Some classes do multiple things. text-xl is:

font-size: 1.25rem;
line-height: 1.75rem;

Some declarations that take 1 line in CSS take multiple classes in Tailwind. border: 1px solid #000; becomes class="border border-black".

Responsive design & pseudo-classes

sm, md, lg, xl, etc all relate to screen sizes, so a class of md:w-1/2 would set width: 50%; at medium screen sizes and up.

hover, focus, etc when prefixed, apply that style just for the pseudo class. A class of hover:text-black would display the text as #000 when it is hovered over. Tailwind ships with plenty of pseudoclass variants that make it super easy to style your elements with interaction.

One thing to note here is that not all pseudoclass variants are generated for all styles due to the huge filesize increase that it would cause. The docs outline which variants are enabled for which classes, but you can always customise it to have exactly what you need.

Isn't this just inline styles?

The truth is that yeah, it sort of is?

But also, not really?

Modern web development has came a long way from being just inline styles.

Part of the reasoning behind Tailwind is to keep you in your HTML, but be sure to leverage whatever tech stack you're using and pull things into partials or components.

Element components

Even with using partials or components, you might think that a load of Tailwind classes to style common elements like headings, paragraphs and links is overkill.

Just styling an a will leave your HTML looking like this:

<a href="/testimonials" class="text-gray-900 underline hover:text-black-900">
  Testimonials
</a>

Repeating this everywhere in your HTML can become pretty tedious. If I'm working in something like React I prefer to turn it into a reusable component:

const A = ({href, children}) => (
  <a href={href} className="text-gray-900 hover:underline hover:text-black-900">
   {children}
  </a>
)

Then rendering it becomes similar to regular HTML:

<A href="/testimonials">Testimonials</A>

Tailwind also has the @apply feature which allows you to extract multiple classes to one common class.

If I'm working in something component based I prefer to pull these into a component and keep the Tailwind class syntax across the project, but @apply can also be useful.

That's a lot of classes

You'd think so, but when you build in production, Tailwind uses PurgeCSS to look through all your files and only include the classes that you actually use.

One thing that initially tripped me up, was that any string concatonation will stop PurgeCSS from finding those classes. As long as you use full class names when doing any logic it will work as expected.

# don't do this
const style = `bg-${resp.ok ? 'green-500' : 'red-500'}`;

# do this
const style = resp.ok ? 'bg-green-500' : 'bg-red-500';

IntelliSense

I'm a VS Code user so it was nice to find an amazing plugin for working with Tailwind. It provides a really great integration for autocompletion, and a whole load of other features.

Install it from the VS Code Marketplace.

An API for your Design System

Although Tailwind ships with lots of classes that do various things, it's all generated from a configuration file.

You can see that configuration by running npx tailwindcss init --full and opening tailwind.config.js. Anything in that file can be changed and Tailwind will generate the appropriate classes. Each section of the docs also explains how to correctly customise each utility.

For most projects, I've gone with the standard classes, but there's nothing stopping you from completely rewriting the config with your own spacing, colours, fonts, etc and using Tailwind to generate classes for your design system.

What can you build with Tailwind?

Unlike other CSS frameworks, there's no such thing as a Tailwind look. Govbins, Conversations with a Shipwreck, Good Club and this site were all built using Tailwind. A big benefit of Tailwind is that it allows you to be more creative and doesn't trap you into a certain style.

If you're a bit lost with how to build more complex UI, there's Tailwind UI. It's a collection of styled elements that you can drop into your HTML and customise. There's a load on there for free along with premium ones that require a paid account.

Wrapping up

Tailwind is a CSS framework to build your own design system, which ships with sensible defaults to generate a good starting point. Give it a shot with your next project and see how it goes.

It took me a while to get used to it, but now it's something that I really enjoy working with.

As the fantastic docs say:

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.
Published 15th April 2021