Tailwind CSS

2023-12-03

For a long time I wrote CSS the traditional way, either in separate stylesheet files or using CSS modules. Recently I started using Tailwind CSS and it has changed how I think about styling.

What Is Tailwind

Tailwind is a utility-first CSS framework. Instead of writing custom CSS classes like .card-header or .primary-button, we compose styles directly in the HTML using small utility classes. Each class does one thing.

For example, instead of writing this in CSS:

.card {
  padding: 16px;
  background-color: white;
  border-radius: 8px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}

We write this in the HTML:

<div class="p-4 bg-white rounded-lg shadow">
  ...
</div>

Each class maps to a CSS property. p-4 is padding, bg-white is background colour, rounded-lg is border radius, and shadow is box shadow.

Why I Like It

The main benefit for me is speed. I do not have to switch between files or come up with class names. The styling is right there in the component. Naming things is one of the harder parts of programming, and with Tailwind I rarely need to invent CSS class names.

Another benefit is consistency. Tailwind uses a design system with predefined spacing, colours, and sizing values. Instead of using arbitrary pixel values like padding: 13px, we use values from the scale like p-3 (12px) or p-4 (16px). This naturally keeps the design consistent across the application.

Dead code is also less of a problem. With traditional CSS, unused styles tend to accumulate over time because we are not sure if they are still needed somewhere. With Tailwind, the styles are in the markup, so when we remove a component, the styles go with it.

Responsive Design

Tailwind makes responsive design straightforward using breakpoint prefixes. If we want a grid that shows one column on mobile and three columns on larger screens:

<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
  ...
</div>

The md: prefix means the style only applies at the medium breakpoint and above. There are prefixes for sm, md, lg, xl, and 2xl.

Customisation

The default Tailwind configuration covers most use cases, but we can customise it in the tailwind.config.js file. We can add custom colours, fonts, spacing values, or extend the existing ones to match our design system.

module.exports = {
  theme: {
    extend: {
      colors: {
        brand: "#1a73e8",
      },
    },
  },
};

After adding a custom colour, we can use it like bg-brand or text-brand anywhere in the markup.

The Trade-Off

The most common criticism is that the HTML looks cluttered with all the utility classes. For components with many styles, the class string can get long. In practice, since we use components in React (or similar frameworks), each component is small and self-contained, so the class strings are usually manageable. For repeated patterns, Tailwind also lets us extract classes using @apply in CSS, though I try to use that sparingly and prefer keeping things in the markup.