Chapter 3 of 14 · Tailwind CSS for Beginners — Complete Free Tutorial
The Utility-First Approach
Knowing how to install Tailwind is only half the story; the harder part is changing how you design. This chapter of the Tailwind CSS for Beginners series explains the utility-first workflow: composing interfaces from tiny single-purpose classes, the two escape hatches that keep you unblocked, and the habits that keep long class lists readable.
What utility-first really means
A utility is a class that does one thing and does it predictably. Instead of writing a stylesheet first and then inventing markup to match it, you start from the interface in your head and reach for small classes that each add a single property. The loop looks like this:
- Sketch the element — a card, a button, a row of stats.
- Ask what each part needs: layout, spacing, colour, type, states.
- Stack the utilities for those answers directly on the markup.
- Adjust by editing the class list, with your browser open beside your editor.
Because the styles sit next to the content, there is no jumping between files to find out why a rule applies, and no unused CSS: everything in the output file was requested by markup you can point at.
Reading a class list
Long class lists are real, but they are not random. Each class is a prefix plus a value, and the prefixes come from a small, memorable set:
| Prefix | Controls | Example |
|---|---|---|
flex, grid, block | Layout and display | grid grid-cols-3 |
p-, m-, gap- | Spacing | px-4 py-2 gap-6 |
text-, font-, tracking- | Typography | text-sm font-semibold |
bg-, border-, rounded- | Colour, borders, surfaces | bg-white border rounded-lg |
hover:, focus:, md: | Conditions (variants) | hover:underline md:text-lg |
When you meet an unfamiliar class, the prefix tells you which page of the documentation to open, and the value tells you which scale to look in.
Building a card, step by step
Here is a complete component written the utility-first way, with each group of classes doing one job:
<article class="max-w-sm rounded-xl border border-slate-200 bg-white p-6 shadow-sm">
<p class="text-xs font-medium uppercase tracking-wide text-indigo-600">New release</p>
<h3 class="mt-2 text-xl font-bold text-slate-900">Designing with utilities</h3>
<p class="mt-2 text-sm leading-6 text-slate-600">A short course on composing interfaces from small, repeatable pieces.</p>
<button class="mt-4 rounded-lg bg-indigo-600 px-4 py-2 text-sm font-semibold text-white hover:bg-indigo-700">
Read now
</button>
</article>
Expected output:
A narrow white card with a thin grey border, rounded corners and a
subtle shadow. It contains a small purple label, a bold dark title,
two lines of grey description, and a solid indigo button that
darkens on hover.
Compare that with the same card written by hand: a .card rule, a .card-label rule, a .btn rule and a hover rule, spread across a separate stylesheet. The utility version states every decision at the point of use, which is why teams that adopt it rarely go back to hunting through nested rules.
Escape hatch 1: arbitrary values
Scales cover most needs, but designs sometimes demand one exact value. Square brackets let you write any CSS value on the spot:
<div class="w-[420px] pt-[13px] text-[#1d4ed8]">
Pixels when the scale will not do
</div>
Expected output:
An element exactly 420px wide with 13px of top padding and text in
a specific shade of blue — no CSS rule written anywhere.
Arbitrary values are a release valve, not a habit. If the same odd number appears three times, promote it to a theme token (chapter 14) so the design stays consistent. A related syntax, bg-(--brand), is shorthand for bg-[var(--brand)] and keeps your own CSS variables handy inside utilities.
Escape hatch 2: variants
A variant is a condition placed before a utility with a colon: hover:bg-indigo-700, focus:ring-2, md:flex, first:mt-0. Variants stack from left to right in v4, so md:hover:underline means "when the screen is medium or larger, and the element is hovered, underline it". Stacking order used to run right to left in v3, which is one of the few places old examples will actively mislead you.
Keeping class lists readable
- Sort by role — layout first, then spacing, then typography, then colour. Consistent ordering beats clever ordering, and a formatter can enforce it.
- One element, one job — if a tag carries twenty classes, part of it wants to be its own component.
- Break the line — long
classattributes can be split across lines in HTML, Blade and JSX so every screen shows whole classes. - Extract when repetition hurts — the moment the same cluster appears three times, it becomes a component class, which chapter 13 handles properly.
Common mistakes
- Recreating a stylesheet in markup — writing forty classes on one div usually means you skipped a layout utility such as
flexorgap-4. - Guessing class names — an invented name compiles to nothing and fails silently, so verify it in the docs rather than trusting your memory.
- Fighting your own CSS — a custom rule and a utility on the same element create specificity wars; remove the custom rule or stop using the utility.
- Copying v3 examples blindly — renamed utilities like
shadow-sm(nowshadow-xs) and right-to-left variant stacking behave differently in v4.
Practice checklist
- Rewrite the card example without looking, then compare your class list with the one here.
- Add a second button to the card that is outlined instead of filled, using only utilities.
- Give the card a
hover:-translate-y-1class and preview how a lift effect feels. - Find one value you typed in square brackets and turn it into a named token in your CSS file.
Now that you can read and write utilities, the next chapter explains the colour system behind classes like indigo-600 — Colors in Tailwind.
Frequently Asked Questions
Tailwind is a utility-first CSS framework: instead of writing custom classes like .card-title, you compose elements from small single-purpose utilities such as text-lg font-semibold text-slate-800. The styles ship as a generated stylesheet containing only the classes your project uses, so the CSS stays small and consistent.
Bootstrap ships a opinionated component layer (buttons, navbars with Bootstrap's own look) that you override with custom CSS. Tailwind ships primitive utilities and lets you design freely — two sites built with Tailwind can look completely different, while two Bootstrap sites tend to look related. You can still build components; you just compose them from utilities first.
You need the fundamentals: the box model, specificity, Flexbox, Grid, media queries and pseudo-classes. Tailwind does not replace CSS knowledge — it renames it. Understanding what padding, margin, gap and z-index mean makes every utility class obvious instead of something to memorise.
v4 is CSS-first: configuration lives in CSS with @import "tailwindcss" and @theme tokens instead of a JavaScript tailwind.config.js, the engine is rewritten in Rust for much faster builds, and modern CSS features (container queries, cascade layers) are built in. This tutorial teaches v4 and notes where v3 differed.
Long class lists are a real trade-off, and the tutorial covers two fixes: consistent ordering (layout → spacing → typography → colour) and small component classes for repeated combinations. The generated CSS contains only classes you actually use — Tailwind removes everything else at build time, so the stylesheet is typically smaller than an unused framework.
Three utilities cover most cases: mx-auto centres a fixed-width block horizontally, flex items-center justify-centre centres children inside a flex parent, and grid place-items-center does the same for grids. Chapter 8 and chapter 9 show both patterns with examples.
Yes — Tailwind is a build step that scans your template files for class names and generates CSS, so it works with any framework or none. It does not ship runtime JavaScript, and the classes look the same in JSX, Blade, PHP or static HTML files.
In v4 you define design tokens in CSS with @theme, for example --color-brand-500: #4f46e5; creates bg-brand-500, text-brand-500 and friends. For a one-off value you can always use arbitrary values like bg-[#0f172a], which need no configuration at all.
A variant prefixes a utility with the condition it applies under: hover:bg-indigo-600 on hover, focus:ring-2 while focused, dark:bg-slate-900 in dark mode, and sm: / md: / lg: at breakpoints. Variants stack, such as md:hover:text-lg, and chapter 11 covers the full pattern.
Yes. Tailwind compiles to a static stylesheet with no JavaScript requirement, and because it ships only used classes, pages stay fast — a Core Web Vitals win that helps SEO. Accessibility, semantic markup and good content remain your job; Tailwind only styles what you write.