After this lesson, you will be able to: Style real UI by composing Tailwind utility classes directly in your HTML, understand WHY utility-first is a paradigm shift away from named-class CSS, and recognize when (and when not) to reach for @apply.
Tailwind CSS is now the default styling system on most professional web projects. The shift is not about shorter class names — it's about WHERE your styling decisions live. In a traditional CSS stack, every component needs a hand-named class plus a CSS rule somewhere else. In Tailwind, components are composed from low-level utility classes in the markup itself, and the only CSS file is Tailwind's generated output. This lesson takes you from never having used Tailwind to fluent in the mental model and able to read most production Tailwind code on sight.
Traditional CSS asks you to invent a name for every visual idea. You make a `.card`, `.card-header`, `.card-body`, then write CSS rules for each. The names try to describe the thing's identity. Utility-first inverts that. Tailwind ships hundreds of tiny single-purpose classes (`p-4`, `text-lg`, `bg-white`, `rounded-xl`, `shadow-sm`) and you build components by combining them directly in the HTML. There are no `.card-header` rules to maintain because there's no `.card-header` — there's just a `div` with five utility classes. The trade-off: your HTML looks longer at first glance. The payoff: changes happen in one place (the markup), naming bikesheds disappear, and dead CSS becomes impossible.
Three rules that take you from confused to comfortable. (1) Trust the utilities. If you find yourself writing a custom CSS rule, ask whether a utility exists for it first — it almost always does. (2) Compose, don't abstract. Repeating `bg-white p-4 rounded-xl shadow-sm` ten times is fine. When that pattern actually solidifies into a reusable component, you abstract it as a React component, not as a CSS class. (3) The HTML is the source of truth. Don't split styling across a `style.css` file AND the markup — pick one home for visual decisions. In Tailwind, that home is the markup.
The CSS-first version (left) requires two files and a name you invented. The Tailwind version (right) is one file, no name, immediately readable.
<!-- CSS-first --><style>.primary-btn {background-color: #FF4848;color: white;padding: 8px 16px;border-radius: 8px;font-weight: 600;}.primary-btn:hover { background-color: #e03e3e; }</style><button class="primary-btn">Save</button><!-- Tailwind, same output, no <style> tag, no invented name --><button class="bg-[#FF4848] hover:bg-[#e03e3e] text-white px-4 py-2 rounded-lg font-semibold">Save</button>
Five categories cover ~80% of real styling. Memorize the prefixes, the rest is filled in by IDE autocomplete.
<!-- Spacing & sizing -->p-4 /* padding: 1rem */px-4 /* horizontal padding */mt-2 /* margin-top: 0.5rem */w-full h-screen /* width 100%, height 100vh */<!-- Typography -->text-sm text-lg text-2xl /* font sizes */font-semibold font-bold /* weight */text-white text-gray-600 /* color */<!-- Backgrounds + borders -->bg-white bg-blue-500 /* solid backgrounds */rounded-lg rounded-full /* corner radius */border border-gray-200 /* 1px border */shadow-sm shadow-md /* drop shadow */<!-- Layout -->flex items-center justify-between gap-3grid grid-cols-3 gap-4space-y-2 /* vertical spacing between children */<!-- State variants -->hover:bg-blue-600focus:ring-2 focus:ring-offset-2disabled:opacity-50
Any utility can be prefixed with a screen size (`md:flex`, `lg:grid-cols-3`) or a state (`hover:bg-blue-600`, `focus:ring-2`, `disabled:opacity-50`). The prefix is the trigger, the utility is the effect. You'll see the full breakpoint system in the responsive design lesson — for now, just recognize that `md:flex` means 'apply flex from the medium breakpoint up.' This is what replaces media queries in Tailwind.
Tailwind has an `@apply` directive that bundles utilities into a named class inside a CSS file. It looks tempting — `.btn { @apply bg-blue-500 text-white px-4 py-2 rounded-lg; }` — but it usually re-introduces the exact problem utility-first solved: a name you have to invent, a CSS file to maintain, two homes for styling. Use `@apply` only when (a) you genuinely cannot make it a component because the markup is in HTML you don't control (rare), or (b) you're styling a third-party component's exposed CSS hook. For anything in your own React/Next.js codebase, make it a `<Button>` component instead.
Build a profile card using Tailwind utilities directly in the markup. No `<style>` tag, no CSS file, no `@apply`. The starter is a bare semantic skeleton — add the utility classes inline. Required patterns below verify you hit the key styling beats: rounded corners, shadow, padding, and a flex layout for the row.
All four produce visually similar output. One follows the utility-first principles best.
Sign in and purchase access to unlock this lesson.