Tailwind CSS Handbook v4.3

Responsive Design

Mobile-first breakpoints, max-width variants, breakpoint ranges, and how to customise the scale with @theme in Tailwind v4.

Tailwind builds responsive design into the class name. Any utility can be prefixed with a breakpoint, and the prefix compiles to a media query.

Overview#

HTML
<img class="w-16 md:w-32 lg:w-48" src="/photo.jpg" alt="">

That is width: 4rem on small screens, 8rem from 48rem up, and 12rem from 64rem up — three media queries, no stylesheet.

Default breakpoints#

PrefixMin widthMedia query
sm40rem (640px)@media (width >= 40rem)
md48rem (768px)@media (width >= 48rem)
lg64rem (1024px)@media (width >= 64rem)
xl80rem (1280px)@media (width >= 80rem)
2xl96rem (1536px)@media (width >= 96rem)

Mobile-first is not optional#

Unprefixed utilities apply at every size. Prefixed utilities apply at that breakpoint and above. There is no "small only" prefix.

HTML
<!-- ✅ Centred on phones, left-aligned from 40rem up -->
<div class="text-center sm:text-left">

<!-- ❌ Unstyled on phones, centred from 40rem up -->
<div class="sm:text-center">

Basic example#

A layout that stacks on phones and splits at the medium breakpoint:

Loading preview…

Targeting a range#

max-* variants#

VariantMedia query
max-sm@media (width < 40rem)
max-md@media (width < 48rem)
max-lg@media (width < 64rem)
max-xl@media (width < 80rem)
max-2xl@media (width < 96rem)
HTML
<!-- Only on phones -->
<div class="max-sm:hidden">Hidden below 40rem</div>

Stacking for a band#

Combine a min and a max variant to target one range exclusively:

HTML
<!-- Flex only between 48rem and 64rem -->
<div class="md:max-lg:flex">…</div>

One-off breakpoints#

HTML
<div class="min-[320px]:text-center max-[600px]:bg-sky-300">…</div>

Use these sparingly. A value that appears twice belongs in your theme.

Customising breakpoints#

Breakpoints live in the --breakpoint-* namespace.

CSS
@import "tailwindcss";

@theme {
  --breakpoint-xs: 30rem;
  --breakpoint-3xl: 120rem;
}

That adds xs:* and 3xl:* — and max-xs:* and max-3xl:* — automatically.

Overriding one value#

CSS
@theme {
  --breakpoint-2xl: 100rem;
}

Removing a default#

CSS
@theme {
  --breakpoint-2xl: initial;
}

Replacing the whole scale#

CSS
@theme {
  --breakpoint-*: initial;
  --breakpoint-tablet: 40rem;
  --breakpoint-laptop: 64rem;
  --breakpoint-desktop: 80rem;
}

Now the variants are tablet:, laptop: and desktop:.

Common patterns#

Responsive navigation#

Loading preview…

hidden md:flex and md:hidden are the workhorse pair for showing one control on mobile and another on desktop.

Fluid card grid#

HTML
<div class="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">…</div>

Responsive type scale#

HTML
<h1 class="text-3xl font-bold tracking-tight sm:text-4xl lg:text-5xl">…</h1>

Fluid sizing without breakpoints#

Sometimes a clamp() beats three breakpoints:

HTML
<h1 class="text-[clamp(1.75rem,1.2rem+2.4vw,3rem)] font-bold">…</h1>

Breakpoints vs container queries#

BreakpointsContainer queries
Responds toViewport widthNearest container's width
Prefixsm: md: lg:@sm: @md: @lg:
Best forPage-level layoutReusable components
Breaks whenA component moves into a narrow slotRarely

Use breakpoints for the page shell and container queries for components that appear in more than one place.

Common mistakes#

  • sm: for mobile. Covered above; it is the single most common error.
  • Prefixing every utility. md:flex md:items-center md:gap-4 when flex items-center gap-4 md:justify-between would do. Only prefix what actually changes.
  • Too many breakpoints. Three well-chosen ones beat five arbitrary ones.
  • Testing only at the breakpoint edges. Bugs live at 700px, not at exactly 768px.
  • Hiding content with hidden and expecting screen readers to skip it. hidden removes it for everyone — that is usually correct, but if the content should be available to assistive tech, use sr-only instead.

Tips#

  • Design the narrow layout first; widening is easier than narrowing.
  • flex-col md:flex-row handles a large share of real responsive work on its own.
  • grid-cols-[repeat(auto-fit,minmax(16rem,1fr))] adapts with no breakpoints at all.
  • Remember print: — it is a variant like any other.