named containers

[check: …]
📖 Pair this live Tailwind demo with the companion guide (.md) — this page is the rendered ground truth. ↗ Builds on tailwind: container queries basics (unnamed @container) — naming is how you disambiguate when containers nest. ↗ See also frontend/tailwind: responsive variants.

nearest ancestor → named ancestor: the disambiguation

An unnamed container variant like @md:grid-cols-2 targets the nearest ancestor carrying class="@container". That rule breaks down once containers nest — a child buried inside a sidebar container plus a main container can't tell them apart. A named container (@container/sidebar) sets container-name: sidebar, and the variant @sm/sidebar: walks past every intermediate container (named or not) until it finds the one named sidebar.

conceptunnamed @containernamed @container/{name}
what gets set container-type: inline-size container-type: inline-size + container-name: {name}
child variant @md:grid-cols-2 @md/sidebar:grid-cols-2
resolution target nearest ancestor with any @container nearest ancestor with @container/sidebar specifically
nested ambiguity ❌ child cannot choose between two enclosing containers ✅ child targets exactly the named one, skipping intermediates
typical use single-container cards, widgets multi-region layouts (sidebar + main), reusable components in varied slots

1 · two named containers, two independent queries

The sidebar container is named sidebar; its child uses @sm/sidebar:grid-cols-2 (fires when sidebar ≥ 384px). The main container is named main; its child uses @md/main:grid-cols-3 (fires when main ≥ 448px). Drag either slider — only that container's named query responds. The other is untouched. That independence is the whole point of naming.

@container/sidebar child: @sm/sidebar:grid-cols-2 (≥ 384px)
350px
@container/main child: @md/main:grid-cols-3 (≥ 448px)
500px

main · 1

Responds to @md/main: only.

main · 2

3rd col appears at ≥ 448px.

main · 3

Independent of sidebar.

container-name: —

sidebar presets:
main presets:

2 · named queries skip intermediate containers

When containers nest, a named variant walks up the tree ignoring every ancestor that doesn't carry the matching @container/{name}. So an unnamed outer container cannot "steal" a query meant for a named inner one.

<!-- unnamed outer container --> <div class="@container"> <!-- named inner container --> <div class="@container/sidebar"> <!-- targets the NAMED "sidebar" ancestor, NOT the outer unnamed one --> <div class="@sm/sidebar:grid-cols-2">…</div> </div> </div>
variant on childwhich ancestor winswhy
@sm:grid-cols-2 (unnamed) nearest @container — here the inner one "nearest" stops at the first container it meets, whatever the name
@sm/sidebar:grid-cols-2 nearest @container/sidebar — skips the unnamed outer name filter; intermediates without the name are transparent to it
@sm/main:grid-cols-2 (no @container/main above) no match — query never fires if no ancestor carries that name, the variant is dead code

Implication: a typo in the name (@sm/sidebr:) silently fails — the query finds no matching container. The gold-check below asserts the exact container-name value to catch this.

intent → pattern

intentpatternwhy
name a container <div class="@container/sidebar"> sets container-name: sidebar + container-type: inline-size
target a named container @sm/sidebar:grid-cols-2 fires when the sidebar container ≥ 24rem (384px), regardless of viewport
two regions, one component @container/sidebar + @container/main same component dropped in either slot adapts to that slot's width
range query on a named container @max-md/sidebar:hidden hide when the named sidebar container < 28rem (448px)
named size container (block-axis units) @container-size/hero use cqb/cqh units against a named size container