

For something like 20 years now, ever since “responsive design” became a thing, developers have been asking for container queries:“Let my component respond to the space it’s given — not the viewport.”
Responsive design has traditionally meant media queries: you style components based on the viewport size. That works — until the same component appears in different contexts (sidebar, grid, modal, CMS block) and suddenly “screen width” is the wrong signal.
Container queries fix that: components can respond to the space they actually get, not the space the browser window has. This makes components genuinely reusable and layout-independent.
What container queries are (and what they’re not)
- Media queries: “If the viewport is at least 1024px…”
- Container queries: “If my parent container is at least 480px…”

The 2 things you need
- A container context on a parent (usually
container-type: inline-size;) - A
@containerrule (optionally targeting a named container)
Your first container query (tiny example)
Here’s a minimal demo: a container that turns a paragraph bold + orange when the container becomes small. Note: I’m using container-type: inline-size (think “width”), because container-type: size applies stronger containment and can collapse unless you explicitly size the element.
That’s the core concept:
- Declare a queryable container with
container-type - Write a
@containerrule. - Style descendants based on the container, not the viewport.
Practical example 2: the “smart card” with container breakpoints + cqi
Now let’s do something real: a card component that adapts when its parent container grows:
- Under 480px, it’s stacked (image on top)
- From 480px, it becomes a split layout (image left, content right)
- From 750px, it gets a nicer background, the title changes color, typography scales, and the button style changes
This example is a component-first responsive card powered by container queries.
The important idea: nothing in this component cares about the viewport. You can place the card in a sidebar, inside a grid column, in a modal, or in a CMS block with limited width — and it will still behave correctly, because it responds to the width of its parent container.
To make this easy to understand, the parent wrapper is also resizable (drag the bottom-right corner). That lets you “simulate” different layout contexts without changing the browser window size.
Step 1: define the container boundary
The container queries only work because the wrapper is declared as a container:
1.resizable-wrapper {2 container-type: inline-size;3 container-name: card-container;4 resize: horizontal;5 overflow: hidden;6}
Why container-type: inline-size?
- It tells the browser: “you can run container queries based on this element’s inline size.”
- In most layouts,
inline-sizeis basically width. - It’s the safest, most practical option for UI components because it avoids some of the stronger containment behavior you get with
container-type: size.
Why a container-name?
Naming the container makes the queries explicit and easier to maintain:
1@container card-container (min-width: 480px) { ... }
Step 2: query the container, not the screen
Instead of @media, we use @container. The card has two container breakpoints:
Breakpoint 1: at 480px
1@container card-container (min-width: 480px) {2 .smart-card {3 flex-direction: row;4 }5}
What changes here:
- The layout shifts from stacked (image on top) to split (image left, content right).
- The image becomes a fixed portion of the width.
- The image height switches from a fixed 200px to height: 100% so it fills the column cleanly.
This is the classic “responsive card” layout change — but triggered by available container space, not the viewport.
Breakpoint 2: at 750px
1@container card-container (min-width: 750px) {2 .card-title {3 font-size: 5cqi;4 color: var(--brand-orange);5 }6}
What changes here:
- The card gets a subtle background gradient (feels more “desktop”).
- Typography bumps up (
.card-descincreases). - Button styling becomes more prominent.
- The title color changes to match branding.
This breakpoint is a good example of something that often looks wrong with media queries: if the component is inside a narrow column on a large screen, you don’t want “desktop styling” just because the viewport is big. You want it only when the component has enough room.
Step 3: cqi units — responsive typography based on the container
This demo also uses container query units:
1.card-title {2 font-size: clamp(1.25rem, 6cqi, 3rem);3}
cqi means: 1% of the container’s inline size.
So as the container grows, the heading grows smoothly — even between breakpoints. This is a nice upgrade over the usual “jump” you get with fixed font sizes at breakpoints.
Then at the larger breakpoint, we intentionally override it:
1@container card-container (min-width: 750px) {2 .card-title {3 font-size: 5cqi;4 }5}
Container query length units (cq*)
Container query length units let you size things relative to the nearest query container, instead of the viewport. They’re the container-based equivalent of vw/vh, which makes them perfect for fluid typography, spacing, and layout details inside reusable components.
If there’s no eligible container in the ancestor chain, these units fall back to the matching small viewport units for that axis
The units:
cqw— 1% of the container’s widthcqh— 1% of the container’s heightcqi— 1% of the container’s inline size (usually width)cqb— 1% of the container’s block size (usually height)cqmin— the smaller ofcqiandcqbcqmax— the larger ofcqiandcqb
Rule of thumb: reach for cqi first (most component sizing follows width), and use cqmin/cqmax when you want scaling to respect the tighter or larger dimension.
Why this matters in real projects
The “smart card” is a example for any real component you build:
- blog cards
- product tiles
- CMS “feature blocks”
- pricing cards
- author blocks
- dashboard widgets
With media queries, these components can break when moved into a new layout. With container queries, the component becomes portable: it adapts based on the space it actually gets, not assumptions about the page.
That’s the real win: container queries move responsive design from page-first to component-first.
Tailwind example
You can use container queries in Tailwind the same way you use responsive utilities — except the breakpoints are based on the size of a parent container, not the viewport. In Tailwind v4, container queries are built-in (no plugin needed).
This demo uses container queries for the grid layout and for each card’s internal layout — so the whole thing responds to the space of the parent container, not the viewport.
In the example below:
- The grid changes column count based on the container width (@sm, @lg, @2xl), so it behaves correctly inside a sidebar, a CMS block, or a constrained layout.
- Each card is its own named container (
@container/card), and switches from stacked → split layout at 480px and applies “desktop polish” at 750px — based on the card’s available space, not the page width.
Note for older Tailwind versions
If you’re on Tailwind v3.2+ (and not v4 yet), container queries are available via the official plugin @tailwindcss/container-queries. As of Tailwind v4, it’s built in and the plugin isn’t required.
Browser support
Container queries are well supported in modern browsers, and for most production sites they’re safe to use today.
Conclusion
With viewport breakpoints, components often end up coupled to page layout assumptions: “this is a sidebar card”, “this is a homepage card”, “this is a modal card”. Over time you collect variants, overrides, and one-off breakpoints that only make sense in one specific page structure.
Container queries flip that around. A component can define its own rules for how it behaves at different sizes, and those rules stay valid no matter where the component is placed — grids, sidebars, dashboard widgets, CMS blocks, or embedded layouts. This is a big win for developers: more portable and reusable components because they adapt to actual available space.
The next time you’re building cards, tiles, or widgets that need to work in multiple contexts, try this approach:
- Make the component look great at the smallest size
- Add one layout breakpoint (eg. stacked → split)
- Polish all other breakpoints (typography + spacing + layout breakpoints)
- Use container units like
cqifor smooth scaling where it makes sense or other when needed
That’s usually enough to get the “wow” benefits of container queries — without turning your UI into breakpoint soup.
In practical terms, this tends to improve three things immediately:
- Fewer brittle breakpoints
You stop “guessing devices” and start reacting to real layout constraints. That’s especially valuable in modern UIs where the same component can appear in 3–10 different contexts. - Cleaner design systems
Components become self-contained. Teams can ship new layouts without rewriting component CSS, and designers can rely on consistent behavior across the system. This aligns with the “responsive components” idea that’s been discussed for years as a way to avoid viewport-driven coupling. - Better progressive enhancement
It’s easier to build a solid default (stacked card) and layer enhancements when space allows. This fits well with how container queries complement media queries rather than replacing them.
If you’re building with Tailwind, container queries feel especially natural: you get the same fast iteration loop as responsive utilities, but you’re making decisions based on the container. Tailwind v4 making this first-class (no plugin) is a good signal that container queries have graduated from “cool new CSS” to a practical tool you can reach for daily.
This pairs really well with modern component stacks like shadcn/ui and Radix Primitives. Radix gives you unstyled, accessible building blocks, and shadcn/ui ships those patterns as copy-pasteable components you fully own—so your components are meant to be reused in lots of different layouts. Container queries complete that story: the same Dialog, Card, or Sidebar widget can adapt based on the space it’s given, not the page it happens to live on.
In other words: Radix provides the structure, shadcn provides the production-ready patterns, Tailwind provides the styling speed, and container queries provide the missing piece—layout independence. Container queries aren’t “a nicer media query” — they’re a shift in where responsiveness lives.

