Utility-first styling: every class does one thing, composability does the rest
Traditional CSS requires you to write styles in a separate file and link them to HTML classes. Tailwind flips this: you apply small, single-purpose utility classes directly in your JSX.
/* styles.css */
.card {
background-color: white;
border-radius: 8px;
padding: 24px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
.card-title {
font-size: 20px;
font-weight: 600;
color: #111;
}<div class="card">
<h2 class="card-title">Hello</h2>
</div><div className="bg-white rounded-lg p-6 shadow-sm">
<h2 className="text-xl font-semibold text-gray-900">Hello</h2>
</div>No separate file. No naming things. Every class does exactly one thing, and you compose them together to build any design.
Tailwind uses a consistent spacing scale based on 4px increments. This applies to padding (p-), margin (m-), width (w-), height (h-), and gap (gap-).
| Class | Value | Pixels |
|---|---|---|
1 | 0.25rem | 4px |
2 | 0.5rem | 8px |
3 | 0.75rem | 12px |
4 | 1rem | 16px |
5 | 1.25rem | 20px |
6 | 1.5rem | 24px |
8 | 2rem | 32px |
10 | 2.5rem | 40px |
12 | 3rem | 48px |
16 | 4rem | 64px |
20 | 5rem | 80px |
24 | 6rem | 96px |
px | 1px | 1px |
Examples: p-4 = 16px padding, mt-8 = 32px margin-top, gap-6 = 24px gap.
| Class | What It Does |
|---|---|
flex | Enable flexbox |
flex-row | Horizontal layout (default) |
flex-col | Vertical layout |
items-center | Center items on cross axis |
justify-center | Center items on main axis |
justify-between | Space items evenly with first/last at edges |
gap-4 | 16px gap between flex children |
flex-1 | Grow to fill available space |
flex-wrap | Allow items to wrap to next line |
| Class | What It Does |
|---|---|
grid | Enable CSS Grid |
grid-cols-2 | 2-column grid |
grid-cols-3 | 3-column grid |
grid-cols-4 | 4-column grid |
col-span-2 | Span 2 columns |
gap-6 | 24px gap between grid items |
| Class | What It Does |
|---|---|
text-xs | 12px font size |
text-sm | 14px font size |
text-base | 16px font size (default) |
text-lg | 18px font size |
text-xl | 20px font size |
text-2xl | 24px font size |
text-3xl | 30px font size |
text-4xl | 36px font size |
font-normal | 400 weight |
font-medium | 500 weight |
font-semibold | 600 weight |
font-bold | 700 weight |
leading-tight | Tight line height (1.25) |
leading-relaxed | Relaxed line height (1.625) |
tracking-tight | Tight letter spacing |
tracking-wide | Wide letter spacing |
text-center | Center-aligned text |
uppercase | Transform text to uppercase |
Tailwind includes a full color palette. Colors follow the format: {property}-{color}-{shade}
text-gray-900 ← Dark gray text
bg-blue-500 ← Medium blue background
border-red-300 ← Light red border
// Common properties:
text-{color} ← Text color
bg-{color} ← Background color
border-{color} ← Border color
// Shade scale: 50 (lightest) → 950 (darkest)
gray-50, gray-100, gray-200, gray-300, gray-400,
gray-500, gray-600, gray-700, gray-800, gray-900, gray-950| Class | What It Does |
|---|---|
rounded | 4px border radius |
rounded-lg | 8px border radius |
rounded-xl | 12px border radius |
rounded-2xl | 16px border radius |
rounded-full | Fully rounded (circle/pill) |
shadow-sm | Small shadow |
shadow | Default shadow |
shadow-lg | Large shadow |
border | 1px border |
border-2 | 2px border |
opacity-50 | 50% opacity |
opacity-0 | Fully transparent |
transition-colors | Animate color changes |
transition-all | Animate all property changes |
duration-200 | 200ms transition duration |
overflow-hidden | Clip overflowing content |
Tailwind lets you apply styles conditionally based on element state. Prefix any utility class with a state variant:
// Hover state
<button className="bg-gray-900 hover:bg-gray-800">
Click me
</button>
// Focus state
<input className="border-gray-300 focus:border-blue-500 focus:ring-2 focus:ring-blue-200" />
// Active state
<button className="bg-blue-500 active:bg-blue-700">
Press me
</button>
// Disabled state
<button className="bg-gray-900 disabled:bg-gray-300 disabled:cursor-not-allowed" disabled>
Can't click
</button>
// Dark mode
<div className="bg-white dark:bg-gray-900 text-gray-900 dark:text-white">
Adapts to color scheme
</div>Tailwind is mobile-first. Styles without a prefix apply to all screen sizes. Prefixed styles apply at that breakpoint and above.
| Prefix | Min Width | Typical Device |
|---|---|---|
sm: | 640px | Large phones |
md: | 768px | Tablets |
lg: | 1024px | Laptops |
xl: | 1280px | Desktops |
2xl: | 1536px | Large desktops |
// Stack on mobile, side-by-side on desktop
<div className="flex flex-col md:flex-row gap-6">
<div className="w-full md:w-1/2">Left</div>
<div className="w-full md:w-1/2">Right</div>
</div>
// 1 column on mobile, 2 on tablet, 3 on desktop
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<div>Card 1</div>
<div>Card 2</div>
<div>Card 3</div>
</div>
// Hide on mobile, show on desktop
<nav className="hidden lg:flex items-center gap-8">
<a href="/about">About</a>
<a href="/work">Work</a>
</nav>You can extend or override Tailwind’s defaults in tailwind.config.ts:
// tailwind.config.ts
import type { Config } from "tailwindcss"
const config: Config = {
content: [
"./app/**/*.{js,ts,jsx,tsx}",
"./components/**/*.{js,ts,jsx,tsx}",
],
theme: {
extend: {
colors: {
brand: {
50: "#fef2f2",
100: "#fee2e2",
500: "#ef4444",
900: "#7f1d1d",
},
},
fontFamily: {
sans: ["Inter", "sans-serif"],
display: ["Space Grotesk", "sans-serif"],
},
borderRadius: {
"4xl": "2rem",
},
animation: {
"fade-in": "fadeIn 0.5s ease-out",
},
keyframes: {
fadeIn: {
"0%": { opacity: "0", transform: "translateY(10px)" },
"100%": { opacity: "1", transform: "translateY(0)" },
},
},
},
},
plugins: [],
}
export default configAfter customizing, you can use your new tokens like any built-in class: text-brand-500, font-display, rounded-4xl, animate-fade-in.