Design and development

Tailwind CSS: why I use it in almost every project, and how I set it up with v4

Why I use Tailwind CSS: design tokens in @theme, generation of only the utilities used, components instead of repeated classes, light and dark themes on variables. With the real limits and the cases where I do not recommend it.

Fabio Folgori7 min read

A fan of colour swatches arranged in sequence
Photo by Mika Baumeister on Unsplash

I use Tailwind CSS in almost every new project, this site included. Not because it is fashionable: after years of stylesheets that grew with every page and class names nobody dared touch, it is the tool that has given me the best balance between development speed, design consistency and CSS weight. Here I explain why, how I set it up with version 4 and, just as frankly, where I do not recommend it.

The problem it solves

A global CSS sheet with no conventions can grow by addition and accumulate conflicts. Semantic names (.product-card, .hero-title) are not the problem in themselves: CSS Modules, scoped styles, layers and other conventions can limit their coupling. Each new page adds rules and exceptions, specificities pile up, and after a few years nobody knows any more what can be removed without breaking a distant page. The result is a file that only grows.

Tailwind moves styling onto the element, with atomic classes that use a finite vocabulary: the project's spacing scale, palette and type sizes. Each class affects only the element it is written on.

Why I use it

Design tokens are the vocabulary

With v4, tokens are defined in CSS, inside @theme: colours, families, spacing scales, radii, shadows. They become CSS variables and feed the project's utilities. Arbitrary values remain possible, so consistency requires conventions and code review. If the project starts from a Figma file with its own variables, these become the theme one by one (I explain it in From Figma to WordPress). To avoid off-system colours I impose conventions on the tokens and check arbitrary values in review.

Utility and variant use drives the CSS size

The published CSS contains only the classes used in the templates. The vocabulary is finite, so a new page reuses existing classes instead of adding rules. The weight depends on the utilities, variants and arbitrary values introduced: a direct benefit for loading and rendering.

Local, safe changes

Changing the utilities of a component limits the effects on the others; changing shared tokens or global styles, however, can modify several parts of the site. For whoever inherits the project, or for an agency entrusting me with part of the work, it is the difference between intervening calmly and being afraid to touch anything.

Responsive, states and container queries in one place

Variants for width, hover, focus-visible, disabled, reduced-motion preference and container queries are written next to the base class. Focus and accessibility states become part of the component, not a forgotten add-on.

How I set it up

Components, not repeated classes

The most common criticism ("the HTML fills up with classes") is fair if you write everything inline. In a Nuxt.js or Vue project every recurring element is a component: the combination of classes for a button lives in a single file. I use @apply sparingly, only for small shared base classes.

Light and dark themes on variables

On this site the light theme does not duplicate classes: it remaps the theme's colour variables. White becomes ink, the grey shades invert, and every component using the tokens changes on its own. The few "islands" that must stay dark (the work slider, the code window, the game) declare the dark theme on their own container. One place to check contrast, instead of hundreds of dark: variants.

Long-form content

Article text comes from Markdown and has no classes: it is handled with a dedicated set of typographic rules applied to the container.

The limits, plainly

  • You need to know CSS. Tailwind does not replace it, it makes it faster to write. Anyone who does not understand flexbox, grid and the cascade will not get there through classes.
  • Without component discipline the markup really does become unreadable.
  • It does not graft well onto ready-made themes and page builders, where styling is decided elsewhere.
  • Very special effects (complex animations, shaders, masks) are still written in dedicated CSS, and rightly so.

When I do not recommend it

On a WordPress site built with a ready-made theme that works, or for a small change to an existing site in traditional CSS, introducing Tailwind makes no sense: better to respect what is there. The tool is chosen for the project, not the other way round.

What changes for whoever commissions the site

You do not need to know what Tailwind is to see its effects:

  1. Lighter pages, because the published CSS contains only what is used: a measurable benefit, especially on phones.
  2. Visual consistency across the site, because colours, spacing and type come from a single token system.
  3. Faster, lower-risk changes: changing a detail does not break distant pages, and the cost of later work stays predictable.
  4. Code others can read: Tailwind is a widespread standard, so an agency or developer coming later finds familiar conventions, not a system I invented.
  5. Light and dark themes, focus states, responsive variants designed with the component, not bolted on at the end.

For an agency there is an extra benefit: the tokens of its own design system become the site's theme, and much less is lost between the design file and the code.

Dynamic classes: what actually ends up in the build

Tailwind looks for strings in the sources, without running the code. Building a class by concatenating prefix, colour and intensity can therefore produce a class missing from the final CSS. I use maps with complete names, for example:

const statuses = {
  confirmed: 'bg-emerald-700 text-white',
  cancelled: 'bg-red-700 text-white',
} as const

External directories and ignored ones require an explicit source configuration when they contain classes to generate. The theme does not prevent arbitrary values either: to keep the design system I check these cases in review.

I verify the CSS of the publishable build, not only the development environment. New utilities, responsive variants and arbitrary values can increase its weight; the trend must be measured.

Reference: class detection in source files, Tailwind CSS.

My take

Tailwind is part of a set of coherent choices: Nuxt.js and Vue for structure, small reusable components, design tokens as the single source of colours and sizes, sites generated in advance and published with GitHub and Netlify. Each one reduces the number of things that can go wrong. It is the same principle that has led me to use fewer and fewer ready-made themes and page builders: fewer layers between design and code, fewer surprises over time.

Why work with me

Since 1999 I have been programming for the web: over 300 projects delivered, many for agencies I work with from Rome and remotely. I use Tailwind with Nuxt.js and Vue for fast, consistent sites that are easy to evolve, and translate designs into components that stay faithful on every screen.

If you have a project to set up properly, get in touch: in a call of about 20 minutes we work out the technical foundation it needs. The service is in Website development.

Frequently asked questions

If you write everything inline on the page, yes. The right way is to extract components: the class combination of a button or card lives in a single component, reused everywhere. The markup stays readable and styling has a single source of truth.

Configuration is written directly in CSS with @theme, tokens become native CSS variables, the engine is faster and Vite integration happens through a dedicated plugin. Less JavaScript configuration, fewer tools to maintain.

In a custom theme, yes, with a build that scans the templates. It makes no sense on a site built with a page builder or ready-made theme, where styling is already decided elsewhere.

No: only the classes actually used in the templates end up in the published file. Stylesheet weight barely grows even as the site grows.

  • #tailwind css
  • #css
  • #design system
  • #nuxt
  • #performance

More articles

// Contact

A project, a problem or just a question?

Agency, business or professional: choose how you'd rather talk to me. I reply as soon as I can, no strings attached.