Skip to content
loke.dev
A card layout changing at its own container boundary instead of the viewport edge

Fix Tailwind Container Query Layout Bugs in Real Components

Understand why a Tailwind container query does nothing or changes the wrong card, then fix the container boundary, query name, and responsive fallback.

Published By Loke3 min read

Container queries fix a very normal component problem: the same card can live in a wide page, a narrow sidebar, or a two-column grid. The viewport is not enough information to decide how the card should look.

When a Tailwind container query does nothing, the class is usually not the interesting part. The missing piece is often the container boundary.

The short fix

Mark the parent as a query container, put the query on the child, and check that the child is actually inside that parent. For size queries, CSS needs container-type: inline-size or the equivalent Tailwind container utility.

<article className="@container">
  <div className="grid gap-4 @md:grid-cols-2">
    <h2 className="text-lg @md:text-2xl">A card that knows its own width</h2>
  </div>
</article>

The @container class creates the boundary. The @md: variants then use that boundary instead of the browser viewport.

Check the nearest container

A query uses the nearest eligible ancestor. If a nested layout adds another container, the child may be measuring a different box than you expected. Inspect the element and walk up the DOM until you find the container-type or container shorthand.

.card-list {
  container: cards / inline-size;
}

@container cards (inline-size > 40rem) {
  .card {
    grid-template-columns: 1fr 1fr;
  }
}

Named containers are not required, but they make larger component trees easier to reason about. They also stop a query from accidentally matching a different ancestor.

Do not confuse viewport and container variants

A normal responsive class such as md:grid-cols-2 uses a viewport breakpoint. A container variant such as @md:grid-cols-2 uses the nearest query container. The two can sit next to each other and look almost the same in a class string.

If the layout changes when you resize the browser but not when you resize the card, you are probably using a media query or the container boundary is missing.

Containment can change sizing

inline-size containment is usually the safe starting point for component layouts. Full size containment also affects the block dimension, so it can change how the element calculates its height. Use the smallest containment type that answers the layout question.

Make the small screen the default

<article className="@container">
  <div className="flex flex-col gap-3 @md:flex-row">
    <div className="min-w-0">Content</div>
    <aside className="w-full @md:w-64">Aside</aside>
  </div>
</article>

The default should still work if container queries are not available or if the component is narrower than the first breakpoint. Then the query only adds roomier layout rules.

A quick debugging checklist

1. Confirm the parent has @container or container: name / inline-size.
2. Confirm the queried element is inside that parent.
3. Check whether a nested container is the nearest one.
4. Make sure you used an @ variant, not a normal viewport variant.
5. Resize the component’s parent, not only the browser window.
6. Test a narrow card in a wide page and a wide card in a narrow sidebar.

Server Componentfetch, secrets, databaseDefault. Keep work and dependencies on the server.
Client ComponentuseState, click, browser APIsAdd 'use client' only at the interactive edge.
A reusable card should respond to the width of its own container, not the page around it.

Container queries are not a magic responsive mode. They are a better question. Instead of asking how wide is the screen, the component can ask how much space do I actually have here?

Sources and further reading

  1. Container queries · Tailwind CSS
  2. CSS container queries · MDN
  3. container-type reference · MDN