Learning Logs · · 3 min read
Learning Tailwind CSS v4: from install to design tokens
Tailwind v4 from this site's real practice: Vite/CLI install, the utility-first mental model, mobile-first responsive, @theme design tokens, and when (not) to use @apply.
Tailwind CSS replaces long CSS files with utility classes right in your HTML. It looks “dirty” at first — until you realize you never think about class naming again, and never fear deleting old CSS. The site you’re reading is built entirely with Tailwind v4; this tutorial is how I use it.
1. Installation (Tailwind v4)
Prerequisite: Node.js 20+. Two paths, pick per project:
With Vite (Vue, React, Astro):
npm install tailwindcss @tailwindcss/vite
// vite.config.js
import tailwindcss from "@tailwindcss/vite";
export default { plugins: [tailwindcss()] };
With the CLI (any project — the way this site does it):
npm install tailwindcss @tailwindcss/cli
npx @tailwindcss/cli -i styles/input.css -o public/site.css --watch
Then one line in your CSS file — in v4 there’s no mandatory tailwind.config.js anymore:
/* styles/input.css */
@import "tailwindcss";
2. The mental model: utilities, not CSS components
<!-- Before: write CSS, name it, maintain it forever -->
<button class="btn-primary">Buy</button>
<!-- Tailwind: the styling reads in place -->
<button class="bg-teal-600 px-4 py-2 text-white hover:bg-teal-700">Buy</button>
The classes you’ll use most in week one: spacing (p-4, mt-6, gap-3), layout (flex, grid, items-center, justify-between), typography (text-sm, font-semibold, tracking-tight), color (bg-*, text-*, border-*).
3. Responsive & states: prefixes, not media queries
<div class="grid grid-cols-1 gap-4 md:grid-cols-3">
<!-- 1 column on phones, 3 columns from 768px up -->
</div>
<a class="text-zinc-500 transition-colors hover:text-zinc-900">Link</a>
The rule is mobile-first: unprefixed classes apply at every size, md: overrides from 768px up. This is the one mental model you must lock in.
4. Design tokens with @theme (v4)
This site’s brand colors are defined once, then become utilities automatically:
@import "tailwindcss";
@theme {
--color-ink: #09090b;
--color-accent: #0d9488;
--font-display: "Geist", sans-serif;
}
Now text-ink, bg-accent, font-display are available everywhere — consistency without extra discipline.
5. Repeated classes? Componentize, don’t @apply
When the same run of classes appears in five places, don’t rush to @apply — extract a component (JSX/Blade/Vue) so markup + styling travel together. I use @apply sparingly, only for global design-system patterns like .btn-primary.
Tips from experience
- Install the Tailwind CSS IntelliSense editor extension — autocomplete + color previews transform the learning experience.
- Tailwind only generates classes it finds written out in scanned files — dynamically assembled classes (
"text-" + color) won’t exist in the output. Write classes in full. - The classic bug that once bit this site: content min-width exceeding a phone’s viewport. Memorize the antidote trio:
min-w-0,truncate, andflex-wrap. - v4 is much faster and CSS-first in configuration — if another tutorial tells you to create
tailwind.config.js+content: [...], that’s v3 style.
Want something like this built for your business?