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#
<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#
| Prefix | Min width | Media query |
|---|---|---|
sm | 40rem (640px) | @media (width >= 40rem) |
md | 48rem (768px) | @media (width >= 48rem) |
lg | 64rem (1024px) | @media (width >= 64rem) |
xl | 80rem (1280px) | @media (width >= 80rem) |
2xl | 96rem (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.
<!-- ✅ 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:
<div class="mx-auto max-w-3xl p-4">
<div class="grid gap-4 md:grid-cols-3">
<div class="rounded-lg bg-indigo-50 p-4 text-sm text-indigo-900 md:col-span-2">
Main content — full width on phones, two of three columns from 48rem up.
</div>
<div class="rounded-lg bg-gray-100 p-4 text-sm text-gray-700">
Sidebar — sits underneath on phones, beside from 48rem up.
</div>
</div>
</div>Targeting a range#
max-* variants#
| Variant | Media 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) |
<!-- 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:
<!-- Flex only between 48rem and 64rem -->
<div class="md:max-lg:flex">…</div>One-off breakpoints#
<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.
@import "tailwindcss";
@theme {
--breakpoint-xs: 30rem;
--breakpoint-3xl: 120rem;
}That adds xs:* and 3xl:* — and max-xs:* and max-3xl:* — automatically.
Overriding one value#
@theme {
--breakpoint-2xl: 100rem;
}Removing a default#
@theme {
--breakpoint-2xl: initial;
}Replacing the whole scale#
@theme {
--breakpoint-*: initial;
--breakpoint-tablet: 40rem;
--breakpoint-laptop: 64rem;
--breakpoint-desktop: 80rem;
}Now the variants are tablet:, laptop: and desktop:.
Common patterns#
Responsive navigation#
<nav class="mx-auto flex max-w-5xl items-center justify-between gap-4 border-b border-gray-200 px-6 py-4">
<span class="font-semibold text-gray-900">Acme</span>
<div class="hidden items-center gap-6 text-sm text-gray-600 md:flex">
<a href="#" class="hover:text-gray-900">Product</a>
<a href="#" class="hover:text-gray-900">Pricing</a>
<a href="#" class="hover:text-gray-900">Docs</a>
</div>
<button class="rounded-md p-2 text-gray-600 hover:bg-gray-100 md:hidden" aria-label="Open menu">
<svg class="size-5" fill="none" stroke="currentColor" stroke-width="1.8" viewBox="0 0 24 24">
<path stroke-linecap="round" d="M4 7h16M4 12h16M4 17h16" />
</svg>
</button>
</nav>hidden md:flex and md:hidden are the workhorse pair for showing one control on mobile and another on desktop.
Fluid card grid#
<div class="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">…</div>Responsive type scale#
<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:
<h1 class="text-[clamp(1.75rem,1.2rem+2.4vw,3rem)] font-bold">…</h1>Breakpoints vs container queries#
| Breakpoints | Container queries | |
|---|---|---|
| Responds to | Viewport width | Nearest container's width |
| Prefix | sm: md: lg: | @sm: @md: @lg: |
| Best for | Page-level layout | Reusable components |
| Breaks when | A component moves into a narrow slot | Rarely |
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-4whenflex items-center gap-4 md:justify-betweenwould 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
hiddenand expecting screen readers to skip it.hiddenremoves it for everyone — that is usually correct, but if the content should be available to assistive tech, usesr-onlyinstead.
Tips#
- Design the narrow layout first; widening is easier than narrowing.
flex-col md:flex-rowhandles 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.
Related topics#
- Container Queries — component-level responsiveness
- Flexbox and Grid — what you are making responsive
- Variant Reference — every breakpoint variant