Chapter 10 of 14 · Tailwind CSS for Beginners — Complete Free Tutorial

Responsive Design with Breakpoints

Every interface you build will be read on a phone first and a monitor second, and Tailwind makes that a matter of prefixes rather than media query blocks. This chapter of the Tailwind CSS for Beginners series covers the built-in breakpoints, the mobile-first habit behind them, how to add screens of your own in v4's theme, and the container queries that take responsiveness a step further. The strategy behind the breakpoints is the same one taught in Responsive Design & Media Queries.

Mobile-first, one prefix at a time

Every responsive utility in Tailwind is a min-width condition: a class with no prefix applies always, and each breakpoint prefix adds a floor. That structure forces the mobile-first habit almost by accident — you write the narrow layout first, then add classes that switch things on when there is more room. There is no desktop-minus syntax to unlearn, and no cascade of overridden rules; the larger variant simply wins when the viewport reaches it.

The default breakpoints

PrefixMinimum widthRoughly
sm:40rem (640px)Large phones in landscape
md:48rem (768px)Tablets and small laptops
lg:64rem (1024px)Laptops and small desktops
xl:80rem (1280px)Common desktop monitors
2xl:96rem (1536px)Very large screens

Two habits keep these useful. First, choose breakpoints where your design breaks, not where a particular device sits — the names are widths, not gadgets. Second, use as few as you can: three prefixes solve almost every layout.

Building a layout that steps up

Here is a small page that starts as a single column and gains structure as space appears — the most common responsive move in the whole framework:

<div class="mx-auto max-w-6xl px-4 py-8">
  <header class="flex flex-col gap-4 md:flex-row md:items-center md:justify-between">
    <h1 class="text-2xl font-bold md:text-4xl">Dashboard</h1>
    <button class="w-full rounded-lg bg-indigo-600 px-4 py-2 text-sm font-semibold text-white md:w-auto">New report</button>
  </header>
  <main class="mt-6 grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3">
    <section class="rounded-xl border border-slate-200 bg-white p-5">Stat</section>
    <section class="rounded-xl border border-slate-200 bg-white p-5">Stat</section>
    <section class="rounded-xl border border-slate-200 bg-white p-5">Stat</section>
  </main>
</div>

Expected output:

On a phone: a stacked header, a full-width button and single-column
cards. At 768px the header becomes one row and the title grows. At
1024px the cards sit three across with even gutters.

Read the class list left to right and it tells the story of the layout: base behaviour first, then the moments it changes, in the order a visitor meets them.

Custom screens in your theme

v4 keeps breakpoints in the same place it keeps every other token, so adding or changing one is a CSS declaration instead of a JavaScript edit:

@import "tailwindcss";

@theme {
  --breakpoint-xs: 30rem;
  --breakpoint-3xl: 112.5rem;
  --breakpoint-md: 50rem;
}

Expected output:

Two new variants appear: xs: and 3xl: now compile in your markup,
while md: begins at 800px instead of 768px. No configuration file is
involved.

Overriding an existing name resizes that breakpoint everywhere it is used, which is powerful and slightly dangerous — change one, then re-test every page that uses it. In v3 the same change meant editing theme.screens inside tailwind.config.js.

Container queries

Width-based breakpoints ask about the viewport, but components often care about the space they have been given: a card in a sidebar and a card in the main column can be on the same screen with very different room. Tailwind v4 supports CSS container queries natively, and the utilities follow the familiar pattern — mark the parent as a container, then query it:

<div class="@container w-full max-w-md border border-slate-200 rounded-xl p-4">
  <div class="flex flex-col gap-4 @sm:flex-row @sm:items-center">
    <div class="size-12 shrink-0 rounded-full bg-slate-300"></div>
    <p class="text-sm text-slate-700">Container queries adapt to the parent, not the window.</p>
  </div>
</div>

Expected output:

On narrow screens the avatar sits above the text. Widen the card
into a wider column — with the window untouched — and the same
markup lays out as a horizontal row instead.

Each container breakpoint is named from the --container-* scale, so @sm: fires at 24rem of container width rather than of viewport. The component decides for itself, and the same markup is reusable in any column.

Testing the whole range

Responsive work is only finished when you have looked at it: drag the window through every breakpoint and watch for content that jumps, wraps badly or scrolls sideways. Dev tools make this cheap — save a 375px phone, a 768px tablet and a 1440px desktop as favourites, and check each layout at all three before calling it done.

Common mistakes

  • Desktop-first thinking — max-width mental models produce classes that fight Tailwind's min-width cascade; write the small screen first.
  • Too many breakpoints — five screens times four components is twenty states to test; most designs settle at two or three prefixes.
  • Changing too much per step — if spacing, colour, type and layout all switch at once, the page feels jumpy; phase changes across steps.
  • Hiding content on phones — removing information instead of restacking it costs you both users and search visibility.
  • Ignoring the middle — testing only at 375px and 1440px hides bugs at tablet widths, where many layouts actually break.

Practice checklist

  1. Take a single-column list and make it two-up at sm: and three-up at lg:.
  2. Resize through every breakpoint and check for horizontal scrolling at each step.
  3. Add a --breakpoint-3xl token and use 3xl:grid-cols-4.
  4. Build a card with @container and confirm it responds to its own width rather than the window.

Layout that adapts is only half the picture; interfaces also react to people — Hover, Focus and Other States.

Quiz: Responsive Design with Breakpoints

5 questions · 70% to pass

Frequently Asked Questions

Tailwind is a utility-first CSS framework: instead of writing custom classes like .card-title, you compose elements from small single-purpose utilities such as text-lg font-semibold text-slate-800. The styles ship as a generated stylesheet containing only the classes your project uses, so the CSS stays small and consistent.

Bootstrap ships a opinionated component layer (buttons, navbars with Bootstrap's own look) that you override with custom CSS. Tailwind ships primitive utilities and lets you design freely — two sites built with Tailwind can look completely different, while two Bootstrap sites tend to look related. You can still build components; you just compose them from utilities first.

You need the fundamentals: the box model, specificity, Flexbox, Grid, media queries and pseudo-classes. Tailwind does not replace CSS knowledge — it renames it. Understanding what padding, margin, gap and z-index mean makes every utility class obvious instead of something to memorise.

v4 is CSS-first: configuration lives in CSS with @import "tailwindcss" and @theme tokens instead of a JavaScript tailwind.config.js, the engine is rewritten in Rust for much faster builds, and modern CSS features (container queries, cascade layers) are built in. This tutorial teaches v4 and notes where v3 differed.

Long class lists are a real trade-off, and the tutorial covers two fixes: consistent ordering (layout → spacing → typography → colour) and small component classes for repeated combinations. The generated CSS contains only classes you actually use — Tailwind removes everything else at build time, so the stylesheet is typically smaller than an unused framework.

Three utilities cover most cases: mx-auto centres a fixed-width block horizontally, flex items-center justify-centre centres children inside a flex parent, and grid place-items-center does the same for grids. Chapter 8 and chapter 9 show both patterns with examples.

Yes — Tailwind is a build step that scans your template files for class names and generates CSS, so it works with any framework or none. It does not ship runtime JavaScript, and the classes look the same in JSX, Blade, PHP or static HTML files.

In v4 you define design tokens in CSS with @theme, for example --color-brand-500: #4f46e5; creates bg-brand-500, text-brand-500 and friends. For a one-off value you can always use arbitrary values like bg-[#0f172a], which need no configuration at all.

A variant prefixes a utility with the condition it applies under: hover:bg-indigo-600 on hover, focus:ring-2 while focused, dark:bg-slate-900 in dark mode, and sm: / md: / lg: at breakpoints. Variants stack, such as md:hover:text-lg, and chapter 11 covers the full pattern.

Yes. Tailwind compiles to a static stylesheet with no JavaScript requirement, and because it ships only used classes, pages stay fast — a Core Web Vitals win that helps SEO. Accessibility, semantic markup and good content remain your job; Tailwind only styles what you write.