Container queries
The sm: and md: prefixes look at the window width. But the same card can sit in a wide main column or in a narrow sidebar. Container queries change styles based on the width of the parent rather than the screen. In Tailwind 4 they are built in and need no plugin.
Container and variant
The parent gets the @container class, and the children get variants with an at sign: @sm:, @md:, @lg: and so on:
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<div class="@container w-64 border border-gray-200 p-2">
<p class="bg-rose-200 p-3 @md:bg-emerald-200">Narrow container</p>
</div>
<div class="@container mt-3 border border-gray-200 p-2">
<p class="bg-rose-200 p-3 @md:bg-emerald-200">Wide container</p>
</div>The classes are the same, yet the first paragraph is pink and the second is green: the first container is only 16rem wide, and @md: starts at 28rem.
Container sizes
| Variant | Container width from |
|---|---|
@xs: | 20rem (320px) |
@sm: | 24rem (384px) |
@md: | 28rem (448px) |
@lg: | 32rem (512px) |
@xl: | 36rem (576px) |
@2xl: | 42rem (672px) |
There are also smaller steps @3xs:, @2xs: and larger ones up to @7xl:. Note that the values differ from the screen breakpoints.
A card that adapts by itself
The product card turns horizontal when it has enough room, wherever it is placed:
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<div class="grid grid-cols-3 gap-4">
<div class="@container col-span-2">
<div class="overflow-hidden rounded-xl bg-white shadow @xs:flex">
<img src="/media/photo-400x250.jpg" alt="Headphones" class="h-32 w-full object-cover @xs:h-auto @xs:w-32">
<p class="p-4 font-semibold">Headphones — $79</p>
</div>
</div>
<div class="@container">
<div class="overflow-hidden rounded-xl bg-white shadow @xs:flex">
<img src="/media/photo-400x250.jpg" alt="Speaker" class="h-32 w-full object-cover @xs:h-auto @xs:w-32">
<p class="p-4 font-semibold">Speaker — $45</p>
</div>
</div>
</div>In the wide cell the image moved to the left of the text, in the narrow one it stayed on top. One card markup works anywhere on the page.
Named containers
When containers are nested, a variant uses the nearest one. To target a specific one, give the container a name after a slash: @container/sidebar, and write @lg/sidebar:flex on the children.
Common mistake
Forgetting the @container class on the parent:
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<div class="border border-gray-200 p-2">
<p class="bg-rose-200 p-3 @sm:bg-emerald-200">Why always pink?</p>
</div>The paragraph never changes: without @container on an ancestor the browser has nothing to measure. The container must be the parent or another ancestor, not the element with the variant itself.