Container Queries
Make a component respond to the width of its container, not the viewport.
Media queries ask “how wide is the screen?” But a card does not care about the screen — it cares about the slot it was dropped into. Container queries, built into v4 core, let a component adapt to its own parent.
Two steps
- Mark the parent a container with
@container. - Prefix child utilities with
@sm:,@md:,@lg:— these now measure the container, not the viewport.
<div class="@container">
<div class="flex flex-col @md:flex-row">
<!-- row once the container is wide enough -->
</div>
</div>Named containers and exact widths
Name a container to target it specifically from deep inside: @container/card on the parent, then @lg/card:grid-cols-2 on a descendant. Need a precise threshold? Use @min-[400px]:.
Why it changes how you build
The same card — identical classes — can sit one-column in a narrow sidebar and two-column in a wide hero, and it just works. That is genuine, portable component reuse, the thing utility CSS was always reaching for.
Example
When to use it
- A product card component switches from a vertical to a horizontal layout when it is placed in a wide column, using container queries instead of viewport breakpoints.
- A sidebar widget hides its secondary text when the sidebar is collapsed to a narrow width, reacting to its container's size rather than the screen size.
- A reusable article card shows a large image on wide containers and a thumbnail on narrow ones without duplicating the component or hard-coding breakpoints.
More examples
Container query setup
@container marks the containment boundary; @md:flex-row switches to a row layout when the container reaches the md width (28rem by default).
<div class="@container">
<div class="flex flex-col @md:flex-row gap-4 p-4 bg-white rounded border">
<img src="thumb.jpg" class="w-full @md:w-32 h-40 @md:h-24 object-cover rounded" alt="">
<div>
<h3 class="font-semibold">Card Title</h3>
<p class="text-sm text-gray-500">Card description text.</p>
</div>
</div>
</div>Named container query
A named container (@container/sidebar) lets the nav label hide when the sidebar container is narrower than 10rem, creating a collapse-to-icons sidebar.
<div class="@container/sidebar w-64">
<nav class="space-y-1">
<a href="/" class="flex items-center gap-2 px-3 py-2 rounded hover:bg-gray-50">
<svg class="w-5 h-5 flex-none"><!-- icon --></svg>
<span class="@[10rem]/sidebar:inline hidden text-sm">Dashboard</span>
</a>
</nav>
</div>Grid inside container query
Container query breakpoints on grid-cols let the inner grid go from one to three columns based on the wrapper's width, not the viewport.
<div class="@container">
<div class="grid grid-cols-1 @sm:grid-cols-2 @lg:grid-cols-3 gap-4">
<div class="bg-sky-50 p-4 rounded">Item 1</div>
<div class="bg-sky-50 p-4 rounded">Item 2</div>
<div class="bg-sky-50 p-4 rounded">Item 3</div>
</div>
</div>
Discussion