11 / 18
All 18 in 18 Tailwind CSS Product Cards
- 01Tailwind Product Card with Hover-Reveal Add to Cart
- 02Pure-Tailwind 3D Flip Product Card with Spec Back
- 03Tailwind Contained Image Zoom Product Card
- 04Tailwind Mouse-Tracking 3D Tilt Product Card
- 05Tailwind Slide-Up Details Panel Product Card
- 06Tailwind Minimalist eCommerce Product Card
- 07Tailwind Glassmorphism Product Card
- 08Tailwind Dark-Mode Gadget Product Card with Accent Glow
- 09Tailwind Neon Glowing Conic-Border Product Card
- 10Tailwind Material-Design Elevation Product Card
- 11Tailwind Horizontal Product Card with Container Queries
- 12Tailwind Auto-Fit Product Catalog Grid
- 13Tailwind Sale Ribbon & Coupon Badge Product Card
- 14Tailwind Sneaker Card with Colourway & Size Picker
- 15Tailwind Digital Download Product Card
- 16Tailwind Food Delivery Card with Quantity Stepper
- 17Tailwind Real Estate Listing Card with Favourite Toggle
- 18Tailwind Subscription Pricing Card with Billing Switch
Tailwind Horizontal Product Card with Container Queries
The cart-row card that responds to its own width instead of the viewport's — and in v4 that is a first-class variant, not a raw @container block. @container/card on the wrapper plus @max-\[420px\]/card:flex-col on the card is the entire responsive story, so the same component works in a wide cart column and a narrow sidebar.
Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time
Untitled UI React · Affiliate link
The code
<section class="tpc-11 w-full min-h-svh grid place-items-center bg-tpc11-bg font-tpc11-sans px-5 py-12" aria-label="Horizontal container-query product card demo">
<div class="@container/card w-[min(520px,100%)]">
<article class="flex rounded-2xl overflow-hidden bg-tpc11-card shadow-[0_14px_36px_-20px_oklch(0.25_0.03_260/0.4)] @max-[420px]/card:flex-col">
<div role="img" aria-label="Product photo: Ridge insulated bottle" class="flex-[0_0_40%] aspect-square bg-linear-[135deg,var(--color-tpc11-ph),var(--color-tpc11-ph2)] bg-[url('https://images.unsplash.com/photo-1602143407151-7111542de6e8?w=700&h=700&fit=crop&q=70')] bg-cover bg-center @max-[420px]/card:flex-none @max-[420px]/card:w-full @max-[420px]/card:aspect-[16/9]"></div>
<div class="flex-1 flex flex-col justify-between gap-4.5 px-5.5 py-5">
<div>
<h3 class="text-[17px] font-semibold leading-[1.35] text-tpc11-ink text-pretty">Ridge Insulated Bottle · 750ml</h3>
<p class="mt-1 text-[13px] text-tpc11-mut">Slate · Keeps cold 24h</p>
</div>
<div class="flex flex-wrap items-center justify-between gap-3">
<p class="text-[20px] font-extrabold text-tpc11-ink tabular-nums">$35</p>
<div class="flex gap-2">
<button type="button" class="min-h-11 h-11 px-4 rounded-[10px] border border-tpc11-edge bg-tpc11-card text-tpc11-ghostink text-[13px] font-semibold cursor-pointer transition-colors duration-150 hover:border-tpc11-acc hover:text-tpc11-acc focus-visible:outline-3 focus-visible:outline-[color-mix(in_oklch,var(--color-tpc11-acc)_45%,oklch(1_0_0))] focus-visible:outline-offset-2 motion-reduce:transition-none">Save</button>
<button type="button" class="min-h-11 h-11 px-4.5 rounded-[10px] border-0 bg-tpc11-acc text-tpc11-onacc text-[13px] font-semibold cursor-pointer transition-colors duration-150 hover:bg-tpc11-acc2 focus-visible:outline-3 focus-visible:outline-[color-mix(in_oklch,var(--color-tpc11-acc)_45%,oklch(1_0_0))] focus-visible:outline-offset-2 motion-reduce:transition-none">Add to Cart</button>
</div>
</div>
</div>
</article>
</div>
</section><section class="tpc-11 w-full min-h-svh grid place-items-center bg-tpc11-bg font-tpc11-sans px-5 py-12" aria-label="Horizontal container-query product card demo">
<div class="@container/card w-[min(520px,100%)]">
<article class="flex rounded-2xl overflow-hidden bg-tpc11-card shadow-[0_14px_36px_-20px_oklch(0.25_0.03_260/0.4)] @max-[420px]/card:flex-col">
<div role="img" aria-label="Product photo: Ridge insulated bottle" class="flex-[0_0_40%] aspect-square bg-linear-[135deg,var(--color-tpc11-ph),var(--color-tpc11-ph2)] bg-[url('https://images.unsplash.com/photo-1602143407151-7111542de6e8?w=700&h=700&fit=crop&q=70')] bg-cover bg-center @max-[420px]/card:flex-none @max-[420px]/card:w-full @max-[420px]/card:aspect-[16/9]"></div>
<div class="flex-1 flex flex-col justify-between gap-4.5 px-5.5 py-5">
<div>
<h3 class="text-[17px] font-semibold leading-[1.35] text-tpc11-ink text-pretty">Ridge Insulated Bottle · 750ml</h3>
<p class="mt-1 text-[13px] text-tpc11-mut">Slate · Keeps cold 24h</p>
</div>
<div class="flex flex-wrap items-center justify-between gap-3">
<p class="text-[20px] font-extrabold text-tpc11-ink tabular-nums">$35</p>
<div class="flex gap-2">
<button type="button" class="min-h-11 h-11 px-4 rounded-[10px] border border-tpc11-edge bg-tpc11-card text-tpc11-ghostink text-[13px] font-semibold cursor-pointer transition-colors duration-150 hover:border-tpc11-acc hover:text-tpc11-acc focus-visible:outline-3 focus-visible:outline-[color-mix(in_oklch,var(--color-tpc11-acc)_45%,oklch(1_0_0))] focus-visible:outline-offset-2 motion-reduce:transition-none">Save</button>
<button type="button" class="min-h-11 h-11 px-4.5 rounded-[10px] border-0 bg-tpc11-acc text-tpc11-onacc text-[13px] font-semibold cursor-pointer transition-colors duration-150 hover:bg-tpc11-acc2 focus-visible:outline-3 focus-visible:outline-[color-mix(in_oklch,var(--color-tpc11-acc)_45%,oklch(1_0_0))] focus-visible:outline-offset-2 motion-reduce:transition-none">Add to Cart</button>
</div>
</div>
</div>
</article>
</div>
</section>@import "tailwindcss";
@theme {
--color-tpc11-bg: #eef1f5;
--color-tpc11-bg: oklch(0.95 0.008 250);
--color-tpc11-card: #ffffff;
--color-tpc11-card: oklch(1 0 0);
--color-tpc11-ink: #101828;
--color-tpc11-ink: oklch(0.23 0.03 260);
--color-tpc11-mut: #5b6678;
--color-tpc11-mut: oklch(0.5 0.025 260);
--color-tpc11-ghostink: #344054;
--color-tpc11-ghostink: oklch(0.4 0.03 260);
--color-tpc11-edge: #d0d5dd;
--color-tpc11-edge: oklch(0.86 0.012 260);
--color-tpc11-ph: #dbe3ee;
--color-tpc11-ph: oklch(0.9 0.02 250);
--color-tpc11-ph2: #c9d5e6;
--color-tpc11-ph2: oklch(0.85 0.03 250);
--color-tpc11-acc: #2f5fbf;
--color-tpc11-acc: oklch(0.52 0.14 260);
--color-tpc11-acc2: #26509f;
--color-tpc11-acc2: oklch(0.45 0.13 260);
--color-tpc11-onacc: #ffffff;
--color-tpc11-onacc: oklch(1 0 0);
--font-tpc11-sans: 'Plus Jakarta Sans', system-ui, sans-serif;
}
.tpc-11 {
width: 100%;
min-height: 100svh;
}
.tpc-11 ::selection {
background: var(--color-tpc11-acc);
color: #fff;
}@import "tailwindcss";
@theme {
--color-tpc11-bg: #eef1f5;
--color-tpc11-bg: oklch(0.95 0.008 250);
--color-tpc11-card: #ffffff;
--color-tpc11-card: oklch(1 0 0);
--color-tpc11-ink: #101828;
--color-tpc11-ink: oklch(0.23 0.03 260);
--color-tpc11-mut: #5b6678;
--color-tpc11-mut: oklch(0.5 0.025 260);
--color-tpc11-ghostink: #344054;
--color-tpc11-ghostink: oklch(0.4 0.03 260);
--color-tpc11-edge: #d0d5dd;
--color-tpc11-edge: oklch(0.86 0.012 260);
--color-tpc11-ph: #dbe3ee;
--color-tpc11-ph: oklch(0.9 0.02 250);
--color-tpc11-ph2: #c9d5e6;
--color-tpc11-ph2: oklch(0.85 0.03 250);
--color-tpc11-acc: #2f5fbf;
--color-tpc11-acc: oklch(0.52 0.14 260);
--color-tpc11-acc2: #26509f;
--color-tpc11-acc2: oklch(0.45 0.13 260);
--color-tpc11-onacc: #ffffff;
--color-tpc11-onacc: oklch(1 0 0);
--font-tpc11-sans: 'Plus Jakarta Sans', system-ui, sans-serif;
}
.tpc-11 {
width: 100%;
min-height: 100svh;
}
.tpc-11 ::selection {
background: var(--color-tpc11-acc);
color: #fff;
}Setup — do this once per project
Skip this if your project already runs Tailwind v4.
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>Compiles in the browser — perfect for a CodePen or a quick test, not for production.
npm install tailwindcss @tailwindcss/vite
npm install tailwindcss @tailwindcss/vite// vite.config.js ("type": "module" in package.json)
import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [tailwindcss()],
})// vite.config.js ("type": "module" in package.json)
import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [tailwindcss()],
})Any v4 setup works — Vite, PostCSS or the CLI. Nothing in this demo is bundler-specific.
@import "tailwindcss";
@theme {
--color-tpc11-bg: #eef1f5;
--color-tpc11-bg: oklch(0.95 0.008 250);
--color-tpc11-card: #ffffff;
--color-tpc11-card: oklch(1 0 0);
--color-tpc11-ink: #101828;
--color-tpc11-ink: oklch(0.23 0.03 260);
--color-tpc11-mut: #5b6678;
--color-tpc11-mut: oklch(0.5 0.025 260);
--color-tpc11-ghostink: #344054;
--color-tpc11-ghostink: oklch(0.4 0.03 260);
--color-tpc11-edge: #d0d5dd;
--color-tpc11-edge: oklch(0.86 0.012 260);
--color-tpc11-ph: #dbe3ee;
--color-tpc11-ph: oklch(0.9 0.02 250);
--color-tpc11-ph2: #c9d5e6;
--color-tpc11-ph2: oklch(0.85 0.03 250);
--color-tpc11-acc: #2f5fbf;
--color-tpc11-acc: oklch(0.52 0.14 260);
--color-tpc11-acc2: #26509f;
--color-tpc11-acc2: oklch(0.45 0.13 260);
--color-tpc11-onacc: #ffffff;
--color-tpc11-onacc: oklch(1 0 0);
--font-tpc11-sans: 'Plus Jakarta Sans', system-ui, sans-serif;
}
.tpc-11 {
width: 100%;
min-height: 100svh;
}
.tpc-11 ::selection {
background: var(--color-tpc11-acc);
color: #fff;
}@import "tailwindcss";
@theme {
--color-tpc11-bg: #eef1f5;
--color-tpc11-bg: oklch(0.95 0.008 250);
--color-tpc11-card: #ffffff;
--color-tpc11-card: oklch(1 0 0);
--color-tpc11-ink: #101828;
--color-tpc11-ink: oklch(0.23 0.03 260);
--color-tpc11-mut: #5b6678;
--color-tpc11-mut: oklch(0.5 0.025 260);
--color-tpc11-ghostink: #344054;
--color-tpc11-ghostink: oklch(0.4 0.03 260);
--color-tpc11-edge: #d0d5dd;
--color-tpc11-edge: oklch(0.86 0.012 260);
--color-tpc11-ph: #dbe3ee;
--color-tpc11-ph: oklch(0.9 0.02 250);
--color-tpc11-ph2: #c9d5e6;
--color-tpc11-ph2: oklch(0.85 0.03 250);
--color-tpc11-acc: #2f5fbf;
--color-tpc11-acc: oklch(0.52 0.14 260);
--color-tpc11-acc2: #26509f;
--color-tpc11-acc2: oklch(0.45 0.13 260);
--color-tpc11-onacc: #ffffff;
--color-tpc11-onacc: oklch(1 0 0);
--font-tpc11-sans: 'Plus Jakarta Sans', system-ui, sans-serif;
}
.tpc-11 {
width: 100%;
min-height: 100svh;
}
.tpc-11 ::selection {
background: var(--color-tpc11-acc);
color: #fff;
}<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap">What changed in the port
Which parts became utilities, which stayed CSS, and why.
- This is the port with the biggest structural win. A wrapper rule plus an
@containerblock become@container/cardand two@max-[420px]/card:variants, and the responsive decision moves onto the elements that actually change. - The container is named. v4 supports unnamed
@max-[…]:variants, but a reusable card that might be nested inside another container needs the explicit reference or it silently answers to the wrong box. flex-[0_0_40%]stays an arbitrary value: the three-part shorthand is clearer as one unit thangrow-0 shrink-0 basis-[40%], and it is how the original expressed it.- The stacked state needs three variants, not one —
flex-colon the card,flex-none w-fulland a newaspect-[16/9]on the media. The CSS version's two rules hid that third change inside a shorthand. - Enhancement over the CSS original: both buttons grew to
min-h-11, the muted text was darkened to clear 4.5:1, and the footer gainedflex-wrapso a long price and two buttons break gracefully instead of overflowing.
Here's a working CSS demo from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Tailwind Horizontal Product Card with Container Queries
Source: https://codefronts.com/components/tailwind-css-product-cards/tailwind-horizontal-product-card-container-queries/
The cart-row card that responds to its own width instead of the viewport's — and in v4 that is a first-class variant, not a raw @container block. @container/card on the wrapper plus @max-\[420px\]/card:flex-col on the card is the entire responsive story, so the same component works in a wide cart column and a narrow sidebar.
## HTML
```html
<section class="tpc-11 w-full min-h-svh grid place-items-center bg-tpc11-bg font-tpc11-sans px-5 py-12" aria-label="Horizontal container-query product card demo">
<div class="@container/card w-[min(520px,100%)]">
<article class="flex rounded-2xl overflow-hidden bg-tpc11-card shadow-[0_14px_36px_-20px_oklch(0.25_0.03_260/0.4)] @max-[420px]/card:flex-col">
<div role="img" aria-label="Product photo: Ridge insulated bottle" class="flex-[0_0_40%] aspect-square bg-linear-[135deg,var(--color-tpc11-ph),var(--color-tpc11-ph2)] bg-[url('https://images.unsplash.com/photo-1602143407151-7111542de6e8?w=700&h=700&fit=crop&q=70')] bg-cover bg-center @max-[420px]/card:flex-none @max-[420px]/card:w-full @max-[420px]/card:aspect-[16/9]"></div>
<div class="flex-1 flex flex-col justify-between gap-4.5 px-5.5 py-5">
<div>
<h3 class="text-[17px] font-semibold leading-[1.35] text-tpc11-ink text-pretty">Ridge Insulated Bottle · 750ml</h3>
<p class="mt-1 text-[13px] text-tpc11-mut">Slate · Keeps cold 24h</p>
</div>
<div class="flex flex-wrap items-center justify-between gap-3">
<p class="text-[20px] font-extrabold text-tpc11-ink tabular-nums">$35</p>
<div class="flex gap-2">
<button type="button" class="min-h-11 h-11 px-4 rounded-[10px] border border-tpc11-edge bg-tpc11-card text-tpc11-ghostink text-[13px] font-semibold cursor-pointer transition-colors duration-150 hover:border-tpc11-acc hover:text-tpc11-acc focus-visible:outline-3 focus-visible:outline-[color-mix(in_oklch,var(--color-tpc11-acc)_45%,oklch(1_0_0))] focus-visible:outline-offset-2 motion-reduce:transition-none">Save</button>
<button type="button" class="min-h-11 h-11 px-4.5 rounded-[10px] border-0 bg-tpc11-acc text-tpc11-onacc text-[13px] font-semibold cursor-pointer transition-colors duration-150 hover:bg-tpc11-acc2 focus-visible:outline-3 focus-visible:outline-[color-mix(in_oklch,var(--color-tpc11-acc)_45%,oklch(1_0_0))] focus-visible:outline-offset-2 motion-reduce:transition-none">Add to Cart</button>
</div>
</div>
</div>
</article>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tpc11-bg: #eef1f5;
--color-tpc11-bg: oklch(0.95 0.008 250);
--color-tpc11-card: #ffffff;
--color-tpc11-card: oklch(1 0 0);
--color-tpc11-ink: #101828;
--color-tpc11-ink: oklch(0.23 0.03 260);
--color-tpc11-mut: #5b6678;
--color-tpc11-mut: oklch(0.5 0.025 260);
--color-tpc11-ghostink: #344054;
--color-tpc11-ghostink: oklch(0.4 0.03 260);
--color-tpc11-edge: #d0d5dd;
--color-tpc11-edge: oklch(0.86 0.012 260);
--color-tpc11-ph: #dbe3ee;
--color-tpc11-ph: oklch(0.9 0.02 250);
--color-tpc11-ph2: #c9d5e6;
--color-tpc11-ph2: oklch(0.85 0.03 250);
--color-tpc11-acc: #2f5fbf;
--color-tpc11-acc: oklch(0.52 0.14 260);
--color-tpc11-acc2: #26509f;
--color-tpc11-acc2: oklch(0.45 0.13 260);
--color-tpc11-onacc: #ffffff;
--color-tpc11-onacc: oklch(1 0 0);
--font-tpc11-sans: 'Plus Jakarta Sans', system-ui, sans-serif;
}
.tpc-11 {
width: 100%;
min-height: 100svh;
}
.tpc-11 ::selection {
background: var(--color-tpc11-acc);
color: #fff;
}
```Here's a working CSS demo from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Tailwind Horizontal Product Card with Container Queries
Source: https://codefronts.com/components/tailwind-css-product-cards/tailwind-horizontal-product-card-container-queries/
The cart-row card that responds to its own width instead of the viewport's — and in v4 that is a first-class variant, not a raw @container block. @container/card on the wrapper plus @max-\[420px\]/card:flex-col on the card is the entire responsive story, so the same component works in a wide cart column and a narrow sidebar.
## HTML
```html
<section class="tpc-11 w-full min-h-svh grid place-items-center bg-tpc11-bg font-tpc11-sans px-5 py-12" aria-label="Horizontal container-query product card demo">
<div class="@container/card w-[min(520px,100%)]">
<article class="flex rounded-2xl overflow-hidden bg-tpc11-card shadow-[0_14px_36px_-20px_oklch(0.25_0.03_260/0.4)] @max-[420px]/card:flex-col">
<div role="img" aria-label="Product photo: Ridge insulated bottle" class="flex-[0_0_40%] aspect-square bg-linear-[135deg,var(--color-tpc11-ph),var(--color-tpc11-ph2)] bg-[url('https://images.unsplash.com/photo-1602143407151-7111542de6e8?w=700&h=700&fit=crop&q=70')] bg-cover bg-center @max-[420px]/card:flex-none @max-[420px]/card:w-full @max-[420px]/card:aspect-[16/9]"></div>
<div class="flex-1 flex flex-col justify-between gap-4.5 px-5.5 py-5">
<div>
<h3 class="text-[17px] font-semibold leading-[1.35] text-tpc11-ink text-pretty">Ridge Insulated Bottle · 750ml</h3>
<p class="mt-1 text-[13px] text-tpc11-mut">Slate · Keeps cold 24h</p>
</div>
<div class="flex flex-wrap items-center justify-between gap-3">
<p class="text-[20px] font-extrabold text-tpc11-ink tabular-nums">$35</p>
<div class="flex gap-2">
<button type="button" class="min-h-11 h-11 px-4 rounded-[10px] border border-tpc11-edge bg-tpc11-card text-tpc11-ghostink text-[13px] font-semibold cursor-pointer transition-colors duration-150 hover:border-tpc11-acc hover:text-tpc11-acc focus-visible:outline-3 focus-visible:outline-[color-mix(in_oklch,var(--color-tpc11-acc)_45%,oklch(1_0_0))] focus-visible:outline-offset-2 motion-reduce:transition-none">Save</button>
<button type="button" class="min-h-11 h-11 px-4.5 rounded-[10px] border-0 bg-tpc11-acc text-tpc11-onacc text-[13px] font-semibold cursor-pointer transition-colors duration-150 hover:bg-tpc11-acc2 focus-visible:outline-3 focus-visible:outline-[color-mix(in_oklch,var(--color-tpc11-acc)_45%,oklch(1_0_0))] focus-visible:outline-offset-2 motion-reduce:transition-none">Add to Cart</button>
</div>
</div>
</div>
</article>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tpc11-bg: #eef1f5;
--color-tpc11-bg: oklch(0.95 0.008 250);
--color-tpc11-card: #ffffff;
--color-tpc11-card: oklch(1 0 0);
--color-tpc11-ink: #101828;
--color-tpc11-ink: oklch(0.23 0.03 260);
--color-tpc11-mut: #5b6678;
--color-tpc11-mut: oklch(0.5 0.025 260);
--color-tpc11-ghostink: #344054;
--color-tpc11-ghostink: oklch(0.4 0.03 260);
--color-tpc11-edge: #d0d5dd;
--color-tpc11-edge: oklch(0.86 0.012 260);
--color-tpc11-ph: #dbe3ee;
--color-tpc11-ph: oklch(0.9 0.02 250);
--color-tpc11-ph2: #c9d5e6;
--color-tpc11-ph2: oklch(0.85 0.03 250);
--color-tpc11-acc: #2f5fbf;
--color-tpc11-acc: oklch(0.52 0.14 260);
--color-tpc11-acc2: #26509f;
--color-tpc11-acc2: oklch(0.45 0.13 260);
--color-tpc11-onacc: #ffffff;
--color-tpc11-onacc: oklch(1 0 0);
--font-tpc11-sans: 'Plus Jakarta Sans', system-ui, sans-serif;
}
.tpc-11 {
width: 100%;
min-height: 100svh;
}
.tpc-11 ::selection {
background: var(--color-tpc11-acc);
color: #fff;
}
```How this works
The container is a utility now. The CSS version needs a wrapper rule (container-type: inline-size) plus a separate @container (max-width: 420px) block. v4 collapses both into the markup:
<div class="@container/card w-[min(520px,100%)]">
<article class="flex @max-[420px]/card:flex-col">
<div class="flex-[0_0_40%] aspect-square @max-[420px]/card:aspect-[16/9]">Both ends of the responsive decision now sit on the element that changes, which is the whole argument for container queries in the first place: the component knows how to be narrow, and the page does not have to tell it.
Why the name matters. @container/card names this container, and @max-[420px]/card: targets it explicitly. Drop this card into a container-queried grid and the unnamed form would resolve against the nearest container — which might be the grid, not the card.
Where it degrades. Without container-query support the card stays in its horizontal layout at every width, which is why the media is flex-[0_0_40%] rather than a fixed pixel width: even unstacked, it never squeezes the body to nothing.
Make it yours
- Stack threshold: the
420pxinside both@max-[…]/card:variants. Tune it to where your image gets too small to read. - Media share:
flex-[0_0_40%]→flex-[0_0_28%]for a thumbnail row,50%for a feature row. - Swap the actions for your cart's real controls — a quantity stepper (see demo 16), remove, save-for-later.
- Add
@min-[560px]/card:variants to grow the type when the card is given a wide column. - Retheme through
--color-tpc11-acc: the ghost button's hover, the CTA fill and both focus rings read it.
Gotchas — read before shipping
- A container query cannot read the element that declares the container —
@container/cardgoes on the wrapper, and the card inside is what responds. - Name your containers. An unnamed
@max-[420px]:resolves against the nearest container ancestor, which changes meaning the moment this card is nested. - Give the media a fixed
aspect-*in both states, or rows in a cart list jog as images load. - Icon-only cart controls need
aria-label. The two buttons here are text, which is the easier correct answer. - Container queries force layout containment on the inline axis — a child with a percentage height inside will not resolve the way it does in a normal flex row.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 16.4+ | 128+ | 111+ |
Container queries: Chrome 105+, Safari 16+, Firefox 110+. Where unsupported the card keeps its horizontal layout at all widths, which is a usable fallback rather than a broken one.