---
title: "Tailwind v4: Responsive Design"
slug: "tailwind-responsive"
category: "frontend"
tags: ["tailwind", "css", "frontend", "responsive", "mobile-first", "breakpoints", "container-queries"]
status: "stable"
last_updated: 2026-05-14
summary: "Build mobile-first layouts with sm:/md:/lg:/xl:/2xl: viewport variants, then reach for container queries when a component needs to respond to its slot."
related: ["[[frontend/tailwind]]", "[[frontend/css]]", "[[frontend/css-container-queries]]", "[[frontend/tailwind-variants]]", "[[frontend/css-grid]]"]
---

## Overview

Tailwind's responsive variants are mobile-first: `sm:` means "at 40rem and above," not "only on small screens." Build the mobile layout as the base, then layer larger breakpoints on top. The parent reference is [[frontend/tailwind]]; for the container query mechanism see [[frontend/css-container-queries]].

## Build mobile, layer up

Every utility without a breakpoint prefix is the mobile style. Breakpoint variants add rules at larger sizes. The pattern is additive, not overriding.

```html
<div class="flex flex-col gap-4 md:flex-row md:gap-8">
  <aside class="w-full md:w-64">Sidebar</aside>
  <main class="w-full md:flex-1">Content</main>
</div>
```

The mobile layout stacks vertically with a small gap. At `md` (48rem and above), it becomes a row with a wider gap and a fixed sidebar. No reset is needed because `flex-col` is the baseline and `md:flex-row` adds to it.

## Know the five breakpoints

Tailwind v4 ships these defaults:

| Variant | Min-width |
|---------|-----------|
| `sm:`   | 40rem (640px) |
| `md:`   | 48rem (768px) |
| `lg:`   | 64rem (1024px) |
| `xl:`   | 80rem (1280px) |
| `2xl:`  | 96rem (1536px) |

Override or extend them in `@theme`:

```css
@theme {
  --breakpoint-sm: 36rem;
  --breakpoint-3xl: 112rem;
}
```

Stick to the defaults unless the design system specifies different values. Inventing extra breakpoints multiplies the class variants each component must handle.

## Prefer container queries over viewport queries for components

Viewport breakpoints work for page shells. Components placed in variable-width slots, like a card in a sidebar versus a card in a three-column grid, should use container queries.

```html
<div class="@container">
  <div class="flex flex-col @md:flex-row gap-4">
    <img class="w-full @md:w-32 rounded-md" />
    <div>Details</div>
  </div>
</div>
```

The `@md:` prefix comes from `@tailwindcss/container-queries`. The component adapts to its container width, not the viewport. The same markup renders correctly in a 240px sidebar and an 800px main column. For the underlying CSS, see [[frontend/css-container-queries]].

## Reserve viewport breakpoints for page-level layout

Viewport breakpoints are the right choice for page-level layout decisions that depend on the screen: hiding a sidebar below a certain width, switching from a single to a multi-column page shell, adjusting the main content max-width.

```html
<body class="grid grid-cols-1 lg:grid-cols-[240px_1fr]">
  <nav class="hidden lg:block">Navigation</nav>
  <main class="px-4 lg:px-8">Content</main>
</body>
```

The sidebar column only makes sense at `lg` and above because it needs enough screen real estate to coexist with the main content. This is a viewport concern, not a component concern.

## Use `max-*:` variants for top-down overrides

v4 adds `max-sm:`, `max-md:`, `max-lg:`, `max-xl:`, and `max-2xl:` as "at or below" breakpoint variants. Use these sparingly; they fight the mobile-first flow.

```html
<div class="p-8 max-sm:p-4">
```

The rule reads: 32px padding normally, but 16px when below `sm`. This is fine for small adjustments. For major layout changes, restructure to be mobile-first instead of adding max-width overrides.

## Avoid breakpoint proliferation on a single element

An element with `text-sm md:text-base lg:text-lg xl:text-xl` is a signal that the type scale needs a fluid value instead.

```html
<!-- Before: four breakpoint variants -->
<h1 class="text-2xl md:text-3xl lg:text-4xl xl:text-5xl">Title</h1>

<!-- After: fluid type with clamp, one class -->
<h1 class="text-fluid-heading">Title</h1>
```

```css
@theme {
  --text-fluid-heading: clamp(1.5rem, 1rem + 3vw, 3rem);
}
```

Fluid type via `clamp()` removes the need for step-wise breakpoints on typography. Add a token for each fluid scale step and use it everywhere.

## Test on real container sizes, not just breakpoints

Most bugs in responsive layouts appear at widths between breakpoints or in components placed in unexpected container widths. Test at intermediate widths by dragging the browser window, not only at the exact breakpoint values.

For container queries, inspect the container's computed width in DevTools to confirm it matches your expectation. A container inside a CSS grid track may be narrower than the viewport even on a wide screen.

## Related

- [[frontend/tailwind]]
- [[frontend/css]]
- [[frontend/css-container-queries]]
- [[frontend/css-grid]]
- [[frontend/tailwind-variants]]
- [[frontend/tailwind-theme]]
