UT Utility Draft
Layout Patterns

Tailwind Container Queries: A Reusable Card Example

Tailwind Container Queries: A Reusable Card Example
tldrIn Tailwind CSS v4, add @container to a wrapper and put container-query variants on its descendants. The component then responds to the wrapper's available width instead of the page's viewport. Start with a usable stacked layout and add a wider arrangement only when the container meets your chosen threshold. Verify the installed version and browser requirements, work on a branch, and review the built result before deployment.

How do you use Tailwind container queries?

In Tailwind CSS v4, add @container to a wrapper and put container-query variants on its descendants. The component then responds to the wrapper's available width instead of the page's viewport. Start with a usable stacked layout and add a wider arrangement only when the container meets your chosen threshold. Verify the installed version and browser requirements, work on a branch, and review the built result before deployment.

This guide uses syntax checked against the official documentation labeled v4.3 and utilities compiled with Tailwind CSS 4.3.0. It assumes an existing working Tailwind build and horizontal writing mode. It is not an installation or migration procedure.

What changes when the parent sets the breakpoint?

A page can have a wide main column and a narrow sidebar at the same viewport width. A reusable card does not necessarily have enough room for two columns in both locations.

Tailwind's container-query documentation supports minimum-size variants, named containers and arbitrary thresholds. The example here uses @min-[30rem] to make the chosen threshold explicit.

The comparison is between the container and 30rem, not the entire browser window. MDN explains that size queries use an eligible ancestor's dimensions; declaring container-type: inline-size establishes the relevant containment context. MDN's container-query guide covers that underlying CSS model.

Use viewport breakpoints for page-level changes, such as moving a sidebar below the main content. Use a container query when a component's arrangement should follow its own allocated space. The existing responsive design guide covers the viewport side of that distinction.

What does the minimal card look like?

The following is an original demonstration, not a production component or a report of user testing. It has two content blocks, no external assets and no JavaScript.

Place the markup in a source file already detected by your existing Tailwind build:

<div class="@container w-[22rem] max-w-full">
  <article class="grid grid-cols-1 gap-4 p-4 @min-[30rem]:grid-cols-[10rem_minmax(0,1fr)]">
    <div>
      <p>Utility notes</p>
      <p>Layout example</p>
    </div>
    <div class="min-w-0">
      <h2>A card that follows its available space</h2>
      <p>The content remains in document order at both sizes.</p>
    </div>
  </article>
</div>

The outer wrapper is the query container. The inner article is the grid whose columns change. Keep those roles separate: the article's query variant needs an eligible ancestor, not a query of its own size.

The base grid-cols-1 creates one grid track. At the threshold, the arbitrary grid definition creates a 10rem first track and a second track that can use the remaining space. Tailwind documents arbitrary track definitions in its grid-template-columns reference. The underscore inside the class token represents the separation between these track definitions.

There are no visual order utilities here. The introductory block precedes the main text in the HTML at both widths.

The wrapper's w-[22rem] makes a narrow demonstration slot. Its max-w-full caps that width at the available containing width. These are ordinary width constraints, separate from the query itself. See Tailwind's width reference and maximum-width reference for those utilities.

How do you demonstrate both layouts on one page?

Duplicate the complete wrapper and article in a local preview. In the second copy, change only w-[22rem] to w-[42rem]. Keep the component's article classes identical.

If the surrounding layout offers sufficient space, the first wrapper is narrower than the 30rem threshold and the second is wider. The first article stacks its blocks; the second uses the two-track definition.

This isolates the intended variable: the width allocated to each component. Do not simultaneously change the text, grid classes and parent padding, because you then have several explanations for a difference.

For numerical inspection, assume a root font size of 16 CSS pixels. The demonstration widths are then:

Wrapper content width Calculation Expected article layout
22rem 22 × 16 = 352 CSS pixels One column
Just below 30rem Less than 480 CSS pixels One column
30rem 30 × 16 = 480 CSS pixels Two tracks
42rem 42 × 16 = 672 CSS pixels Two tracks

These are calculated expectations under the stated font-size assumption, not measurements from a browser test. A narrower containing layout can reduce the wrapper through max-w-full. Inspect the actual width rather than assuming the requested 42rem was available.

The example puts padding on the inner article, not on the query wrapper. MDN's @container reference specifies that size comparisons measure the container's content box. Keeping the wrapper unpadded makes this first inspection easier to interpret.

What CSS should the build produce?

The example's query and arbitrary grid utilities were compiled with Tailwind CSS 4.3.0 using the package's default stylesheet. Compilation verifies that the tokens are recognized and emit the intended declarations; it does not verify browser rendering, accessibility or your application's source detection.

The relevant generated rule contains this condition and declaration:

@container (width >= 30rem) {
  grid-template-columns: 10rem minmax(0,1fr);
}

This is an excerpt from inside the utility's selector, not a complete stylesheet to paste into a project. The selector and other generated rules have been omitted for readability.

The wrapper utility also emits:

container-type: inline-size;

If your browser receives no relevant query rule, the first problem is generation or stylesheet loading. If the rule exists but does not apply, examine the ancestor and its measured width. Those are different failure paths.

Keep the full class token literal. Do not assemble the threshold or track values from string fragments. The dynamic class-name guide handles the separate source-detection problem in detail.

How do named containers change nested behavior?

A nested query container can become the ancestor used by an unnamed query. When the component intentionally follows a particular outer wrapper, name that wrapper and name it in the variant.

This small example was also checked with the 4.3.0 compiler:

<div class="@container/preview w-[42rem] max-w-full">
  <div class="@container w-full">
    <div class="grid grid-cols-1 gap-4 @min-[30rem]/preview:grid-cols-2">
      <p>First block</p>
      <p>Second block</p>
    </div>
  </div>
</div>

Here preview identifies the intended ancestor. The compiled condition is @container preview (width >= 30rem). The inner unnamed container does not replace that name requirement.

MDN documents how a container name filters the candidate containers in its @container reference. Choose a component-specific name when nesting makes the relationship ambiguous. Naming every wrapper is unnecessary for the first, single-container example.

Do not add a name solely to hide an unexpected ancestor. Inspect the markup first and decide which allocation of space the component is meant to follow.

Why is container different from @container?

Tailwind's container utility constrains an element's maximum width according to the current breakpoint. It does not serve the same purpose as the query-container utility.

Tailwind's maximum-width documentation also notes that container does not automatically add centering or horizontal padding. Neither that utility nor max-w-full substitutes for @container in this example.

This distinction matters during review: a wrapper called "container" in a component file may have a sizing class but no query containment declaration. Inspect the computed container-type, not the variable name.

What should you check before using the pattern?

Use a local preview or branch and check the following cases. These are editorial acceptance checks for this demonstration, not an exhaustive accessibility or compatibility test.

  1. Narrow and wide placements together. Confirm both copies use the same article classes while their wrapper widths differ.
  2. Threshold boundaries. Inspect just below, at and above the measured threshold. Confirm that the wider grid appears at the intended boundary.
  3. Restricted outer space. Narrow the page until the wider wrapper is capped. Confirm the component returns to its base layout.
  4. Long and sparse content. Replace the demonstration text with your longest real heading and with a short entry. Review wrapping and overflow.
  5. Actual nesting. Insert the component into its intended parent structure and confirm which ancestor the query uses.
  6. Zoom and text settings. Recheck readability and the available width rather than relying solely on the calculated pixel table.

Do not infer full browser compatibility from one successful container query. Tailwind's compatibility documentation lists framework-level browser requirements and notes that individual modern features may have additional support limitations. Check the browsers your project actually supports.

The compiler check here did not run your build integration or render the component. Your final verification must include both generated output and the application preview. No dependency upgrade, cache deletion or production deployment is necessary to inspect this pattern.

More component arrangements belong in Layout Patterns. For this one, the acceptance condition is specific: identical card markup changes columns when its intended ancestor crosses the chosen width, independently of another copy elsewhere on the same page.

Sources

FAQ

Does this example require an extra container-query plugin?

The demonstrated utilities compiled with the Tailwind CSS 4.3.0 package and its default stylesheet, without an additional plugin. That result does not establish the setup required by an older project. Identify the installed version and follow its matching documentation rather than adding or removing dependencies to imitate this example.

Can the same card have two layouts at one viewport width?

Yes. In the example, one copy sits in a wrapper requesting 22rem and another in a wrapper requesting 42rem. When sufficient outer space is available, the first remains below the 30rem query threshold and the second exceeds it. Both article elements can retain exactly the same utility classes.

Why does my 42rem wrapper still show the stacked layout?

The requested width is not necessarily the available width. In this example, max-w-full can cap the wrapper inside a narrower parent. Inspect its actual content width and the relevant generated rule. Also confirm the article has the intended query-container ancestor and that another rule is not overriding the grid definition.

Are the pixel values fixed across every project?

No. The worked table explicitly assumes a root font size of 16 CSS pixels: 30rem then equals 480 CSS pixels. Inspect the actual root font size and container dimensions in your preview. Do not convert the table into a universal device breakpoint or assume that a requested wrapper width was achieved.

Does a successful compiler check prove the card is ready to deploy?

No. The reported check establishes that Tailwind CSS 4.3.0 recognized the demonstrated tokens and generated the expected declarations. It does not test your application, browser rendering, content or accessibility. Work on a branch, inspect generated output and test the component in its real placements and supported browsers before deployment.