Tailwind CSS
Tailwind CSS is a utility-first framework: instead of writing custom selectors, you compose designs from small, single-purpose classes applied directly in markup (flex, pt-4, text-blue-600). The build step scans your files and ships only the utilities you actually use.
The payoff is speed and consistency — you style without inventing class names or context-switching to a stylesheet, and a shared config keeps spacing, color, and type on a fixed scale. The cost is busier markup, which you tame by extracting components.
TL;DR
- Build UI from utility classes in markup; the build purges unused ones.
- Get consistency from a config-driven design system (spacing, color, type scales).
- Extract components for repeated patterns instead of copying long class strings.
- Tailwind doesn't replace layout or accessibility fundamentals — you still need them.
Quick Example
A styled button composed entirely from utilities, including a hover state:
Core Concepts
- Utilities — one class, one job: spacing, color, typography, layout.
- Responsive variants — prefix by breakpoint:
md:flex,lg:grid-cols-3. - State variants —
hover:,focus:,disabled:,dark:. - Design tokens — colors, spacing, and fonts live in config, so the whole app shares one scale.
- Content scanning — the build reads your templates and generates only the classes it finds.
Best Practices
Componentize repeated patterns
Don't paste the same 12-class string everywhere — wrap it in a React/Vue/Svelte component (or use @apply for a true CSS component) so the pattern has one home.
Stay on the scale
Prefer the built-in spacing/type/color scales over arbitrary values (mt-[13px]). Consistency is the whole point; reach for arbitrary values only when genuinely needed.
Use @apply sparingly
@apply is handy for a few repeated patterns, but overusing it recreates the sprawling stylesheets Tailwind exists to avoid.
Comparison
Common Mistakes
Dynamically constructed class names
Giant duplicated class lists
FAQ
Doesn't utility-first just mean ugly, bloated markup?
The markup is busier, but you trade it for no naming, no dead CSS, and built-in consistency. Extracting components keeps templates readable, and the shipped CSS is tiny because unused utilities are purged.
How does Tailwind keep the CSS small?
It scans your configured content files at build time and generates only the utilities you actually use, so the final stylesheet contains just your app's classes — usually a few kilobytes.
When should I use @apply?
For a handful of genuinely repeated patterns where a component isn't a natural fit. If you find yourself rebuilding whole component stylesheets with @apply, you've drifted back to traditional CSS.
Tailwind or CSS Modules / CSS-in-JS?
Tailwind for rapid, consistent styling with a shared design system. CSS Modules when you prefer writing standard CSS with local scoping. CSS-in-JS when you need heavily dynamic, prop-driven styles — ideally a zero-runtime option.
Related Topics
- CSS Fundamentals — What utilities map onto
- Sass/SCSS — The preprocessor alternative
- CSS-in-JS — Component-scoped styling in JS
- Web Performance — Why purged CSS helps
- React — Where component extraction happens
References
- Tailwind CSS — Documentation
- Tailwind — Reusing styles
- Tailwind — Content configuration
- Refactoring UI (by Tailwind's creators)