Reusable Components Query Their Container
SHOULD: A reusable component must respond to ITS OWN width, not the viewport: `md:flex-row` asks about the browser window, so the card that reads right in the main column goes horizontal inside a 300px sidebar. Put `@container` on the wrapper and `@md:` on the children — now it asks "is my container ≥28rem", with no `isCompact` prop threaded through three layers. Container queries are core in v4; installing `@tailwindcss/container-queries` is a mistake, not a dependency. The `@` variants read the nearest `@container` ANCESTOR, so the wrapper must not be the element you are sizing.
Size a reusable component against its own container with @container and @md:, not against the viewport
<div class="@container">
<div class="flex flex-col @md:flex-row">…</div>
</div>Bad
Good
Why it matters
A breakpoint variant like `md:flex-row` asks a question about the browser window, but a reusable `<Card>` does not live in the browser window — it lives in whatever box you dropped it into. So the card that looks right in the main column goes horizontal inside a 300px sidebar, because the *viewport* is 1400px wide and the card has no idea it is not. The component is not broken; the question it is asking is.
Container queries let it ask the right one: put `@container` on the card's wrapper and the `@md:flex-row` on its child now means "when my container is at least 28rem", which is true in the main column and false in the sidebar, with no props, no context, and no `isCompact` boolean threaded through three layers. This is core in v4 — installing `@tailwindcss/container-queries` is now a mistake, not a dependency.
Two things to keep straight: the `@` variants read the nearest `@container` ancestor, so the wrapper must be a different element from the one you are sizing; and named containers (`@container/sidebar` with `@md/sidebar:`) exist for when containers nest and you need to skip past the nearest one.