What is Container queries?

Container queries: Container queries let CSS style an element based on the size of its parent container rather than the viewport, so a card adapts to the column it sits in.

Media queries ask how wide the viewport is. Container queries ask how wide the box the component sits in is, which is the question a component actually needs answered. The same card is 320px wide in a sidebar and 900px wide in the main column of the same page; a media query cannot tell those apart, a container query can. The feature is supported in most browsers, and it changes how reusable components are written: the component carries its own breakpoints, and the page no longer needs to know them.

How it works

css
.card-grid > * {
  container-type: inline-size;
  container-name: card;
}
.card { display: grid; gap: 1rem; }
@container card (min-width: 28rem) {
  .card { grid-template-columns: 160px 1fr; }
}
.card h3 { font-size: clamp(1rem, 4cqi, 1.5rem); }
  • `container-type: inline-size` turns an element into a query container for its width. It applies size containment on that axis, so the container's width cannot depend on its contents; it must get its size from its parent, a grid track or an explicit value.
  • `@container (min-width: ...)` styles descendants of the nearest matching container. A container-name lets a rule target a specific ancestor instead of the nearest one.
  • Container units: cqw and cqi are 1 percent of the container's width or inline size, cqh and cqb its height or block size, and they work anywhere a length does, which makes them a good base for fluid typography inside components.
  • Style queries (@container style(--variant: compact)) switch on a custom property's value instead of a size. Support is newer and narrower than for size queries, so check before relying on them.

In Tailwind CSS v4

Tailwind v4 has container queries built in. @container on the parent sets container-type: inline-size, and @md:grid-cols-2 applies at the md container size, with the same names as the viewport breakpoints but prefixed with @. Named containers use @container/card on the parent and @md/card: on the descendants, and arbitrary sizes use @min-[30rem]:.

tsx
<article className="@container rounded-xl border border-border p-4">
  <div className="grid gap-4 @md:grid-cols-[160px_1fr]">
    <img className="aspect-video w-full rounded-lg object-cover" src="/cover.jpg" alt="" />
    <div>
      <h3 className="text-base font-medium @lg:text-lg">Quarterly review</h3>
      <p className="text-sm text-fg-muted">Fits a sidebar or a full column.</p>
    </div>
  </div>
</article>

Pitfalls

  • A container cannot size itself by its contents on the queried axis. A flex item with container-type: inline-size and no width basis collapses. Give it flex: 1, min-width: 0 or a grid track.
  • The container is not styled by its own query. Rules inside @container apply to descendants of the container, not to the container itself. Wrap the component in an extra element when it needs to style its own root.
  • Nesting resolves to the nearest ancestor container of the right type, which may be a parent component's wrapper rather than the one you meant; name containers when components nest.

MiniDev's Card header is declared a named container (@container/card-header) so the title, description and action can be rearranged with @sm/card-header: variants, and dashboard pieces such as StatCard, ChartCard and KpiRow are meant to be dropped into ResizablePanels and grids of any width. The layout category has the containers themselves.

CarduiShadcn compatible card with header, title, description, action, content and footer slots, a compact size and edge to edge images. Built for Tailwind v4.npx shadcn@latest add @minidev/cardStat CarduiReact stat card with a label, optional icon, a large tabular value and a delta chip colored by its sign, with invertDelta for metrics like churn or latency.npx shadcn@latest add @minidev/stat-card