Skip to content

Tailwind CSS v4 Container Queries — Container-Based Responsive Design

DodaTech Updated 2026-06-28 5 min read

In this tutorial, you will learn about Tailwind CSS v4 Container Queries. We cover key concepts, practical examples, and best practices to help you master this topic.

Tailwind CSS v4 container queries are built-in without plugins, using the @container CSS at-rule and container query prefixes (@sm:, @md:, @lg:) for styling based on element container width.

What You'll Learn

You will learn how to define containers, use container query variants, create container-aware responsive components, combine container queries with other variants, and customize container sizes.

Why It Matters

Container queries enable truly reusable components that adapt to their parent's width, not the viewport. DodaTech's dashboard widgets use container queries to rearrange layouts regardless of where they are placed on the page.

Real-World Use

Doda Browser's widget system uses container queries so weather widgets, news cards, and analytics panels rearrange their internal layout based on their container width in any dashboard configuration.

flowchart LR
    A[Dark Mode] --> B[Container Queries]
    B --> C[@container]
    B --> D[@sm @md @lg]
    B --> E[Custom Sizes]
    B --> F[Composition]
    style B fill:#38bdf8,stroke:#0284c7,color:#fff
    style C fill:#22c55e,stroke:#16a34a,color:#fff

Defining Containers

@import "tailwindcss";

/* @container directive is built-in - no configuration needed */
<!-- Define a container with @container class -->
<div class="@container max-w-4xl mx-auto p-4">
  <!-- Children use container query variants -->
  <div class="grid grid-cols-1 @sm:grid-cols-2 @md:grid-cols-3 gap-4">
    <div class="bg-blue-100 p-4 rounded">Item 1</div>
    <div class="bg-blue-200 p-4 rounded">Item 2</div>
    <div class="bg-blue-300 p-4 rounded">Item 3</div>
  </div>
</div>

Expected output: The grid changes columns based on the @container width, not the viewport width. @sm activates at 40rem container width.

Container Query Variants

<div class="@container p-4 bg-gray-50 rounded-lg">
  <div class="
    flex flex-col
    @sm:flex-row
    @md:items-center
    @lg:gap-8
    gap-4
  ">
    <div class="w-full @sm:w-32 @md:w-40 bg-blue-100 p-4 rounded">
      Sidebar
    </div>
    <div class="flex-1">
      <h2 class="text-lg @md:text-xl @lg:text-2xl font-bold">Responsive Title</h2>
      <p class="text-gray-600 mt-2 @md:mt-4 text-sm @md:text-base">
        Content that adapts to container width.
      </p>
      <div class="flex flex-col @sm:flex-row gap-2 mt-4">
        <button class="bg-blue-600 text-white px-4 py-2 rounded">Action</button>
        <button class="border px-4 py-2 rounded @lg:px-6">Secondary</button>
      </div>
    </div>
  </div>
</div>

Expected output: The card layout, text size, spacing, and button sizing all respond to the container's width using @sm:, @md:, @lg: prefixes.

Custom Container Sizes

@import "tailwindcss";

@theme {
  /* Custom container query breakpoints */
  --container-xs: 20rem;
  --container-sm: 30rem;
  --container-md: 40rem;
  --container-lg: 50rem;
  --container-xl: 60rem;

  /* Custom name */
  --container-narrow: 35rem;
  --container-wide: 55rem;
}
<div class="@container max-w-2xl mx-auto p-4">
  <div class="
    grid grid-cols-1
    @xs:grid-cols-1
    @narrow:grid-cols-2
    @wide:grid-cols-4
    gap-4
  ">
    <div class="bg-blue-100 p-4 rounded">Custom breakpoints</div>
    <div class="bg-blue-200 p-4 rounded">Based on @theme values</div>
    <div class="bg-blue-300 p-4 rounded">@narrow at 35rem</div>
    <div class="bg-blue-400 p-4 rounded">@wide at 55rem</div>
  </div>
</div>

Expected output: Container query prefixes use the breakpoints defined in @theme. @narrow: and @wide: become available as custom container query prefixes.

Combining Container Queries with Variants

<div class="@container p-4">
  <div class="
    bg-white dark:bg-gray-800
    @sm:dark:bg-gray-700
    @md:hover:shadow-lg
    @lg:focus:scale-105
    p-6 rounded-lg transition-all
  ">
    <h3 class="font-bold">Combined Variants</h3>
    <p class="text-gray-600 dark:text-gray-300 mt-2">
      Container queries work with dark: hover: focus: and other variants.
    </p>
  </div>
</div>

Expected output: Container query prefixes combine with other variants: @sm:dark:bg-gray-700 applies dark background only when the container is at least sm size.

Nested Containers

<div class="@container p-4 border rounded-lg">
  <h2 class="text-xl font-bold @md:text-2xl">Outer Container</h2>

  <div class="grid grid-cols-1 @md:grid-cols-2 gap-4 mt-4">
    <!-- Each card can be its own container -->
    <div class="@container p-4 bg-gray-50 rounded-lg">
      <div class="flex flex-col @sm:flex-row gap-3">
        <div class="w-full @sm:w-16 h-16 bg-blue-100 rounded-lg"></div>
        <div>
          <h3 class="font-bold @sm:text-lg">Nested card</h3>
          <p class="text-sm text-gray-600">This card has its own container context.</p>
        </div>
      </div>
    </div>

    <div class="@container p-4 bg-gray-50 rounded-lg">
      <div class="flex flex-col @sm:flex-row gap-3">
        <div class="w-full @sm:w-16 h-16 bg-green-100 rounded-lg"></div>
        <div>
          <h3 class="font-bold @sm:text-lg">Independent responsive</h3>
          <p class="text-sm text-gray-600">Each container context is independent.</p>
        </div>
      </div>
    </div>
  </div>
</div>

Expected output: Nested containers have independent container query contexts. Each card's layout adapts based on its own container width, not the outer container.

Container Query @apply

@import "tailwindcss";

.card-base {
  @apply p-4 rounded-lg bg-white dark:bg-gray-800;
}

.card-responsive {
  @apply card-base;
  @apply @sm:flex @sm:gap-4 @md:p-6 @lg:p-8 @lg:text-lg;
}
<div class="@container">
  <div class="card-responsive">
    <div class="w-full @sm:w-24 h-24 bg-blue-100 rounded-lg"></div>
    <div class="flex-1">
      <h3 class="font-bold">Card with @apply</h3>
      <p class="text-gray-600">Container query variants work inside @apply too.</p>
    </div>
  </div>
</div>

Expected output: @apply rules can include container query variant prefixes, enabling component classes with built-in container responsiveness.

Common Mistakes

1. Forgetting @container on Parent

Container query prefixes only work inside elements with the @container class. Without it, @sm:, @md:, @lg: do nothing.

2. Adding @container to the Element Being Styled

@container goes on the parent element. Children use @sm: to respond to the parent's container width.

3. Confusing @sm with sm:

@sm: is container-based. sm: is viewport-based. They can coexist but target different sizing contexts.

4. Not Setting a Container Type

Custom containers may need explicit container-type: container-type: inline-size. Use @container class which sets this automatically.

5. Nesting Without Consideration

Deeply nested containers create multiple contexts. Each @container creates a new containment context, overriding parent contexts.

Practice Questions

  1. How do you define a container in v4? Add the @container class to the parent element. Children use @sm:, @md:, @lg: prefixes.

  2. What does @sm: reference in container queries? The container's width, not the viewport. @sm activates at 40rem container width by default.

  3. How do you customize container query breakpoints? Define --container-sm, --container-md, etc. in @theme.

  4. Can container queries combine with dark mode? Yes: @sm:dark:bg-gray-800 applies dark background when container is sm+ in dark mode.

  5. Do container queries work in @apply? Yes: @apply @sm:flex @sm:gap-4; includes container query variants.

Challenge

Build a reusable dashboard widget component with: @container parent, grid layout using @sm: and @md:, responsive typography with @lg:, nested container for child cards, and combined dark mode variants.

FAQ

Do container queries work in all browsers?

Container queries are supported in Chrome, Edge, Firefox, and Safari 16+. Check CanIUse for legacy browser support.

What is the difference between container queries and media queries?

Media queries respond to viewport size. Container queries respond to the element's container size, enabling truly reusable components.

Can I use container queries with CSS Grid?

Yes. Container query variants work with grid, flex, and any layout method.

How do I debug container queries?

Use DevTools to inspect the container element and verify its container-type. Resize the container to test breakpoints.

Do container queries affect performance?

Container queries have minimal performance impact. They are part of the CSS spec and optimized by browser engines.

Mini Project

Build a responsive widget system: 3 widget types (weather, news, stats) each using @container for layout. Widgets rearrange their internal layout based on container width. Include a dashboard that places widgets in different-sized containers.

What's Next

Now master New Utilities in v4 for the latest utility additions. Then explore Custom Themes for creating complete design systems.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro