Getting Started
Tailwind CSS Fundamentals
Chapter 1 · Why Utility-First, and Getting Set Up
Tailwind CSS gives you a large set of small classes, each doing one job, and you style a page by putting them in your HTML: p-4 for padding,
text-white for a white text colour, rounded-lg for rounded corners. A tool reads your files, finds the classes you used, and writes a
CSS file containing only those. This chapter does the practical part first: build something, look at exactly what Tailwind produced, and learn how it decides what
to produce. Everything after this chapter is learning which classes exist and how to combine them.
index-DqPXTuJK.css
change with the content. The Play CDN example was run in headless Chrome. Anything I did not run is labelled. This course uses Tailwind v4;
the older v3 style (a tailwind.config.js file) is what CSS Frameworks 3 describes.
What a Utility Class Is
A utility class does one small thing, named after what it does. Here is a box with four of them:
The second box is the CSS Tailwind generated for those four classes (copied from the real output file, which you will meet in a moment). Each class is one
rule, and each rule reads from a theme variable: --spacing is 0.25rem, so p-4 is four of those, 1rem. The names
are short because you will type them hundreds of times: p is padding, bg is background, text is text colour (or size,
depending on the value that follows), and the number is a step on a scale.
The argument for working this way, and the usual objection to it ("my markup is full of classes"), is made in CSS Frameworks 2, so it is not repeated
here. In one sentence: you stop inventing names for things and stop switching between your HTML and a stylesheet, and in return you accept longer
class attributes. The rest of this course shows how to keep that trade-off comfortable.
Your First Build with the CLI
The Tailwind CLI is the simplest way to see what Tailwind does, because nothing sits between you and the output. You need Node.js. In an empty folder:
Two files go in src. The CSS file is one line, and it is the whole of Tailwind's setup in v4:
The page uses the classes. It links output.css, which does not exist yet:
Now build:
Open src/index.html in a browser: a large bold underlined heading and a blue rounded box with white text. That is a working Tailwind project. The
two flags are -i (input) and -o (output); add --minify for a smaller file when you publish.
What Is in the File Tailwind Wrote
Open output.css. For this page it is 5,676 bytes, or 5,009 bytes with --minify. It is organised into
cascade layers, which you can see with one command:
The second line declares the order: theme first, utilities last, and a later layer beats an earlier one no matter how specific the
selectors are. That is why a utility such as p-4 reliably overrides the reset in the base layer. The layers hold:
- theme: the variables your page uses, and only those.
- base: Tailwind's reset (called Preflight), the same for every page.
- utilities: one rule for each class Tailwind found in your files.
- properties: a few internal variables (the
--tw-…ones) that some utilities share.
The theme layer for this page is short, because the page uses few things:
Two things to notice. Tailwind has hundreds of colours, sizes and radii in its default theme, but the file contains only the ones this page needs:
--color-blue-500 and --color-white, not the whole palette. And the colours are written in oklch(), a modern colour
notation; browsers have only supported it for a few years, which is part of why Tailwind has browser requirements (see the end of this chapter). Chapter 9 shows how to add
your own theme variables.
base layer resets what browsers do by default. Among its rules, headings lose their size and weight, and lists lose their bullets:
So an <h1> with no classes looks like body text, and a <ul> has no bullets: every visual decision is yours to make with
a class. The same layer also zeroes margins and padding on everything, sets box-sizing: border-box, and makes images
display: block with max-width: 100%. If a page looks "unstyled" after you add Tailwind, this layer is almost always the reason, and
Exercise 3 below makes you read it.
How Tailwind Finds Your Classes
Tailwind does not run your code. It reads your project's files as plain text, looks for strings that match one of its class names, and generates a rule for each
match. Two things follow. First, a class that is not in your files is not in the output: delete p-4 from the page, rebuild, and the
.p-4 rule is gone (I checked: grep -c "\.p-4" printed 0). Second, the class has to appear in the file as a
whole word. This is the mistake that catches everyone once:
Those three lines are the utilities Tailwind generated from that file. bg-green-500 is there because it is written out; bg-red-500
is not, because the text bg-red-500 never appears in the file, only the pieces bg- and -500. (p-2
is there because that part is written whole.) The fix is to write complete class names, even if it looks repetitive; Exercise 2 shows a tidy way to do it.
Chapter 1 of Tailwind CSS Intermediate/Advanced covers the other options for classes Tailwind cannot see.
Which files does it read? By default it scans the project folder you run it from, and it skips some things. I tested this in a small git project with five
files that each used a different margin class: src/a.html (m-1), ignored.html (m-9, listed in
.gitignore), node_modules/pkg/index.html (m-8), notes.css (m-7) and pic.png
(m-6, really a text file with a picture's extension). Only one class made it into the output:
Files in .gitignore, anything in node_modules, stylesheets and binary-looking files (images) are skipped. When I removed the
.gitignore line and rebuilt, .m-9 appeared. Keep this in mind when a class works in one place and not another: the file may be
ignored.
Watch Mode
Running the build by hand after every change gets tedious. Add --watch and the CLI stays running and rebuilds when a file changes:
-w, --watch[=always], "use always to keep watching when stdin is closed".
With --watch=always it built the file, then rebuilt each time I edited the page (the log showed a "Done" line for each build). If a watch task in your
editor, a task runner or a container seems to do nothing, try --watch=always.
Using Tailwind with Vite
Most projects use a bundler, and Tailwind has a plugin for Vite. The Tailwind installation docs list Laravel, SvelteKit, React Router, Nuxt and SolidJS as frameworks that use this route; it is a good default whenever your project already runs on Vite. Install the plugin, add it to the Vite config, and import Tailwind in your CSS. No PostCSS configuration is needed:
The page links the stylesheet (<link href="/src/style.css" rel="stylesheet">), and a normal Vite build does the rest. For the same
one-heading page:
The CSS comes out at 4.77 kB (1.63 kB compressed) and is already minified, with the same layers as before. Notice that a framework with its own build, such as Astro or Next.js, needs its own variation of these steps; those are covered in Tailwind CSS Intermediate/Advanced 5. I did not run the Vite dev server in this chapter; the build above is what I ran.
The Play CDN: Prototypes Only
For a five-minute experiment you can skip the build entirely. One script tag loads Tailwind into the page, and it generates the CSS in the browser as you go:
The second box is what I measured in headless Chrome with and without the script: with it, text-3xl gave 30px (1.875rem) and
underline took effect; without it, the browser's default heading showed. The Tailwind documentation says the Play CDN "is designed for development
purposes only, and is not intended for production", because the browser does the work on every page view and downloads the script each time. Use it to try
a class; use the CLI or Vite for anything you will publish. It also needs a network connection, which is a reason not to depend on it in a course exercise,
so the exercises here use the CLI.
Which Way Should I Use?
| Route | What it is | Use it for | Run here? |
|---|---|---|---|
| CLI | One command: input CSS in, output CSS out; --watch, --minify | Plain HTML sites, learning, small projects, back-end templates | Yes |
| Vite plugin | @tailwindcss/vite in vite.config; build and dev server handle the rest | Any project that already uses Vite (many frameworks do) | Build: yes |
| Framework setups | PostCSS plugin or webpack plugin for tools that are not Vite-based (Next.js, for example) | Whatever your framework's build uses | No (Tailwind CSS Intermediate/Advanced 5) |
| Play CDN | One <script> tag; CSS generated in the browser | Quick experiments and demos only | Yes (headless Chrome) |
Editor Setup
Two tools are worth installing before you write much markup. The Tailwind CSS IntelliSense extension for VS Code (extension ID
bradlc.vscode-tailwindcss) gives class-name completion, shows the CSS a class produces when you hover it, and warns about conflicting classes.
The Prettier plugin for Tailwind (npm package prettier-plugin-tailwindcss) sorts the classes in each class
attribute into a consistent order, so that two people writing the same element produce the same text. Both are described, with their settings, in the
VS Code Tailwind CSS Cheat Sheet in the Sidebar (Programming). I did not install them for this chapter.
Browser Support
Tailwind v4 is built for current browsers. The official compatibility page lists the versions the core framework depends on: Chrome 111
(March 2023), Safari 16.4 (March 2023) and Firefox 128 (July 2024). You have already seen why in the output file: it uses
cascade layers (@layer), registered custom properties (@property) and oklch() colours. A few utilities go further and use
very new CSS, such as field-sizing: content; the same page says to use those only if your audience's browsers support them. If you must support
older browsers than these, v4 is not the right tool, and the v3 line is.
One last difference from older tutorials, since you will meet them: in v3 the CSS file began with three lines (@tailwind base;,
@tailwind components;, @tailwind utilities;) and a tailwind.config.js file held the settings. In v4 it is the single
@import "tailwindcss"; line you used above, and the settings live in the CSS itself. That is the subject of chapter 9.
Hands-On Exercises
In an empty folder, set up the Tailwind CLI from scratch and build a page with a heading (text-2xl font-semibold) and a link styled as a button (inline-block rounded-md bg-teal-600 px-4 py-2 text-white hover:bg-teal-700). From the output file alone, prove three things: the rule for bg-teal-600 exists, the hover rule is wrapped in @media (hover: hover), and the two teal colours appear as variables in the theme layer.
A script builds badge classes with `bg-${color}-500 text-white px-2` for red, green and blue. Build it and show that no background colour is generated, then change the script (without changing what it displays) so that all three are.
Build a page with an <h1>, a two-item <ul> and an <img> and no classes at all. Find the three Preflight rules in the output that explain how each element will look. Then add classes to the list so it has bullets and indentation again, and report which utility rules Tailwind generated.
Chapter 1 Quick Reference
- A utility class does one small job (
p-4,text-white,rounded-lg); Tailwind writes a CSS rule for each class it finds in your files, and only those - v4 setup is one CSS line:
@import "tailwindcss";(v3 used three@tailwindlines and a JS config file) - CLI:
npm install tailwindcss @tailwindcss/cli, thennpx @tailwindcss/cli -i ./src/input.css -o ./src/output.css;--minifyfor production;--watchto rebuild on change, and--watch=alwayswhen standard input is closed - Vite:
@tailwindcss/vitein thepluginsarray,@import "tailwindcss";in your CSS - Play CDN (
@tailwindcss/browser@4): prototypes only, never production - The output has layers in the order
theme,base,components,utilities;themeholds only the variables you use;baseis Preflight, the reset - Tailwind reads files as text: write class names in full (
bg-red-500, neverbg-${color}-500); it skips.gitignored files,node_modules, stylesheets and images - Needs Chrome 111, Safari 16.4 or Firefox 128 or newer
- Editor:
bradlc.vscode-tailwindcss(IntelliSense) andprettier-plugin-tailwindcss(class sorting)
p-4, width and height, and the typography utilities for
size, weight, line height and spacing.