Tailwind CSS — A Practical Guide¶
What this is: a from-scratch guide to Tailwind CSS — what it is, why people use it, how to install and use it, and the patterns you'll meet daily. Written for engineers and QAs who can read HTML/CSS but are new to the "utility-first" approach.
1. What Is Tailwind CSS?¶
Tailwind CSS is a utility-first CSS framework. Instead of giving you pre-built components (like a "card" or "button" class as Bootstrap does), it gives you thousands of tiny single-purpose utility classes that you compose directly in your HTML to build any design.
<!-- Traditional CSS: write a class, then style it in a .css file -->
<button class="btn-primary">Save</button>
<!-- Tailwind: compose utilities inline -->
<button class="bg-teal-600 text-white font-semibold px-4 py-2 rounded-lg hover:bg-teal-700">
Save
</button>
Each class does exactly one thing: bg-teal-600 sets the background colour, px-4 sets horizontal padding, rounded-lg rounds the corners, hover:bg-teal-700 darkens on hover.
flowchart LR
A["Traditional CSS<br/>semantic classes<br/>(.card, .btn)"] -->|"write custom CSS<br/>for every component"| B["growing .css files"]
C["Tailwind<br/>utility classes<br/>(px-4, bg-teal-600)"] -->|"compose in markup<br/>no custom CSS"| D["styles live with the HTML"]
2. Why Use It? (and when not to)¶
| Strengths | Trade-offs |
|---|---|
No naming fatigue — no inventing .card-header-inner-wrapper class names |
Verbose markup — long class="..." strings |
| Styles co-located with markup — no jumping between files | Learning curve — you must learn the utility vocabulary |
| Consistent design system — spacing/colour come from a fixed scale | Can look "ugly" in raw HTML diffs |
| Tiny production CSS — unused classes are stripped out automatically | Best paired with components to avoid repetition |
Responsive & state variants built in (md:, hover:, dark:) |
Not ideal for tiny static pages where plain CSS is simpler |
Use Tailwind when: building component-based apps (React, Vue, Svelte), rapid prototyping, or any project where a consistent design scale matters. Skip it when: a one-page static site where a few lines of plain CSS would do, or a project already committed to a different styling approach.
Note for this portal: this very site is built with Material for MkDocs, which uses traditional CSS (see our
extra.css), not Tailwind. Tailwind shines in app frameworks — the contrast is a good way to understand both approaches.
3. The Mental Model — Utility-First¶
You stop thinking "what component is this?" and start thinking "what does it look like?" — then spell that out with utilities.
<div class="max-w-sm rounded-xl shadow-md bg-white p-6">
<h2 class="text-xl font-bold text-slate-900">Pricing</h2>
<p class="mt-2 text-sm text-slate-600">Simple, transparent pricing.</p>
<button class="mt-4 w-full bg-indigo-600 text-white py-2 rounded-lg
hover:bg-indigo-700 transition">
Get started
</button>
</div>
Read it like a sentence: max-width small, extra-rounded corners, medium shadow, white background, padding 6 → a heading that's extra-large, bold, dark slate → a paragraph with top margin, small, muted → a button…
4. Installation & Setup¶
Tailwind ships as a build tool that scans your files and generates only the CSS you actually use. The modern setup (Tailwind v4) is the simplest it has ever been.
Option A — Vite / framework project (recommended)¶
// vite.config.js
import tailwindcss from '@tailwindcss/vite';
export default { plugins: [tailwindcss()] };
Then import that CSS in your app entry point and start using classes.
Option B — Tailwind CLI (no framework)¶
npm install tailwindcss @tailwindcss/cli
npx @tailwindcss/cli -i ./src/input.css -o ./dist/output.css --watch
Option C — Play CDN (prototyping only, never production)¶
<script src="https://cdn.tailwindcss.com"></script>
<h1 class="text-3xl font-bold text-teal-600">Hello Tailwind</h1>
v3 vs v4: older projects (v3) use a
tailwind.config.jsfile plus three@tailwind base; @tailwind components; @tailwind utilities;directives. v4 replaces that with the single@import "tailwindcss";and CSS-based configuration. If you see@tailwinddirectives in a codebase, it's v3.
5. The Core Utility Vocabulary¶
You don't memorise all of them — you learn the prefixes and the scale. Most numeric utilities use a spacing scale where 1 = 0.25rem (4px), so p-4 = 16px padding.
Spacing — margin & padding¶
| Class | Effect |
|---|---|
p-4 |
padding: 1rem (all sides) |
px-6 / py-2 |
horizontal / vertical padding |
pt-3 pr-2 pb-3 pl-2 |
individual sides |
m-4 / mx-auto |
margin / center horizontally |
gap-4 |
gap between flex/grid children |
space-y-4 |
vertical spacing between children |
Typography¶
| Class | Effect |
|---|---|
text-sm text-lg text-3xl |
font size |
font-bold font-medium |
font weight |
text-center text-right |
alignment |
text-slate-600 |
colour (palette + shade 50–950) |
leading-relaxed |
line height |
tracking-tight |
letter spacing |
uppercase truncate |
transforms |
Colours¶
Tailwind ships a full palette: slate, gray, red, orange, amber, yellow, lime, green, emerald, teal, cyan, sky, blue, indigo, violet, purple, pink, rose — each with shades 50 (lightest) → 950 (darkest).
<p class="text-red-500 bg-red-50 border border-red-200">Error</p>
<span class="text-teal-700">Brand colour</span>
Prefixes: text- (font), bg- (background), border- (border), ring- (focus ring), from-/to- (gradients).
Sizing¶
| Class | Effect |
|---|---|
w-full w-1/2 w-64 |
width (full, fraction, fixed) |
h-screen h-10 |
height |
max-w-md min-h-screen |
constraints |
6. Layout — Flexbox & Grid¶
This is where Tailwind saves the most time.
Flexbox¶
<!-- horizontal row, items centered, space between -->
<div class="flex items-center justify-between">
<span class="font-semibold">Logo</span>
<nav class="flex gap-4">
<a href="#">Home</a>
<a href="#">Docs</a>
</nav>
</div>
| Class | Effect |
|---|---|
flex |
display: flex |
flex-col |
stack vertically |
items-center |
align cross-axis center |
justify-between justify-center |
main-axis distribution |
flex-wrap |
allow wrapping |
flex-1 |
grow to fill |
Grid¶
<!-- responsive card grid: 1 col on mobile, 3 on desktop -->
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
<div class="...">Card</div>
<div class="...">Card</div>
<div class="...">Card</div>
</div>
| Class | Effect |
|---|---|
grid |
display: grid |
grid-cols-3 |
3 equal columns |
col-span-2 |
item spans 2 columns |
gap-6 |
gap between cells |
7. Responsive Design — Mobile-First Breakpoints¶
Tailwind is mobile-first: an unprefixed utility applies to all sizes; a prefixed one applies from that breakpoint up.
<div class="text-base md:text-lg lg:text-xl">
Small on phones, larger on tablets, largest on desktop
</div>
| Prefix | Applies from | Typical device |
|---|---|---|
| (none) | 0px | mobile |
sm: |
640px | large phone |
md: |
768px | tablet |
lg: |
1024px | laptop |
xl: |
1280px | desktop |
2xl: |
1536px | large desktop |
Key mindset: style the mobile layout first with unprefixed classes, then add
md:/lg:overrides for bigger screens — not the other way around.
8. State & Conditional Variants¶
Prefix any utility to make it conditional. They stack.
<button class="bg-teal-600 hover:bg-teal-700 focus:ring-2 focus:ring-teal-300
active:scale-95 disabled:opacity-50 transition">
Submit
</button>
<!-- dark mode -->
<div class="bg-white text-slate-900 dark:bg-slate-800 dark:text-slate-100">
Adapts to dark mode
</div>
<!-- style children / siblings -->
<div class="group">
<p class="text-slate-500 group-hover:text-teal-600">Hover the parent</p>
</div>
| Variant | Meaning |
|---|---|
hover: focus: active: |
interaction states |
disabled: checked: |
form states |
dark: |
dark colour scheme |
md: lg: |
responsive (combinable: md:hover:) |
group-hover: |
react to a parent's hover |
first: last: odd: even: |
structural |
9. Avoiding Repetition — Components & @apply¶
Long class lists repeated everywhere is the #1 Tailwind complaint. Two solutions:
Extract a component (the preferred way)¶
In a framework, wrap the markup once and reuse it:
// Button.jsx — define the classes once
function Button({ children }) {
return (
<button className="bg-teal-600 text-white font-semibold px-4 py-2
rounded-lg hover:bg-teal-700 transition">
{children}
</button>
);
}
// usage: <Button>Save</Button>
@apply — fold utilities into a CSS class¶
For plain HTML or shared primitives:
.btn-primary {
@apply bg-teal-600 text-white font-semibold px-4 py-2 rounded-lg
hover:bg-teal-700 transition;
}
Guidance: prefer component extraction over
@apply. Overusing@applyrecreates the very "custom CSS soup" Tailwind aims to avoid — reach for it only for small, truly reused primitives.
10. Customisation — The Theme¶
Tailwind's scales (colours, spacing, fonts) are a design system you can extend. In v4, you configure in CSS with @theme:
@import "tailwindcss";
@theme {
--color-brand: #0d9488; /* enables bg-brand, text-brand, etc. */
--font-display: "Inter", sans-serif;
--spacing-18: 4.5rem; /* enables p-18, m-18 */
}
For arbitrary one-off values, use square-bracket notation (no config needed):
<div class="top-[117px] bg-[#1da1f2] grid-cols-[1fr_500px_2fr]">
Exact values when the scale doesn't have what you need
</div>
11. A Complete Example — A Responsive Card¶
Putting it together — a production-style component with layout, responsive behaviour, states, and dark mode:
<article class="max-w-sm mx-auto bg-white dark:bg-slate-800 rounded-2xl
shadow-md hover:shadow-xl transition-shadow overflow-hidden">
<img src="cover.jpg" alt="" class="h-40 w-full object-cover" />
<div class="p-6">
<span class="inline-block text-xs font-bold uppercase tracking-wide
text-teal-700 bg-teal-50 px-2 py-1 rounded-full">
Tutorial
</span>
<h3 class="mt-3 text-lg font-bold text-slate-900 dark:text-white">
Getting started with Tailwind
</h3>
<p class="mt-2 text-sm text-slate-600 dark:text-slate-300 leading-relaxed">
A utility-first workflow that scales from prototype to production.
</p>
<a href="#" class="mt-4 inline-flex items-center gap-1 text-sm font-semibold
text-teal-600 hover:text-teal-700">
Read more →
</a>
</div>
</article>
12. Tooling & Testing Notes¶
- IntelliSense: install the official Tailwind CSS IntelliSense VS Code extension — autocomplete, hover previews, and linting for class names.
- Prettier plugin:
prettier-plugin-tailwindcssauto-sorts class names into a canonical order, keeping diffs clean. - For QA / automation: Tailwind classes are presentational, so never use them as test selectors — a restyle (
bg-teal-600→bg-emerald-600) would break your tests. Select bydata-testid, ARIA role, or text instead. See API Testing with Playwright and Playwright Framework Tutorial for robust selector practices. - Visual regression: because Tailwind centralises the design scale, visual-regression snapshots are stable as long as the theme tokens don't change — a good fit for screenshot diffing.
13. Quick Reference¶
| Need | Utility |
|---|---|
| Padding / margin | p-4 px-6 m-2 mx-auto |
| Text size / weight | text-lg font-bold |
| Colour | text-slate-700 bg-teal-600 |
| Flexbox | flex items-center justify-between gap-4 |
| Grid | grid grid-cols-3 gap-6 |
| Sizing | w-full max-w-md h-screen |
| Rounding / shadow | rounded-lg shadow-md |
| Responsive | md:flex lg:text-xl |
| States | hover: focus: disabled: dark: |
| Arbitrary value | w-[137px] bg-[#0d9488] |
| Reuse | component extraction or @apply |
14. Where to Go Next¶
- Official docs: tailwindcss.com/docs — the searchable utility reference is your daily companion
- Interactive: play.tailwindcss.com — a live playground, no setup
- Playwright Framework Tutorial — testing the UIs you build
- TypeScript Cheat Sheet — the language behind most Tailwind-based apps