GooseUI

Adaptive Grid

Grid that adapts layout based on container size and content using Container Queries and :has() selector.

Browser Support

Combines @container queries for responsive sizing with :has(img) to change layout based on content.

Preview

Cards adapt layout based on container width and content.

Wide container

Card with Image

Card with Image

This card has an image, so it expands on wider containers.

Text Only Card

This card has no image, so the layout is compact.

Narrow container

With Image

With Image

Image adapts to narrow space.

Installation

npm
pnpm
yarn
bun
npx shadcn@latest add @gooseui/adaptive-grid

Usage

import { AdaptiveGrid, AdaptiveCard } from "@/components/ui/adaptive-grid"

<AdaptiveGrid>
  <AdaptiveCard title="Card with image" image="/image.jpg">
    Description text
  </AdaptiveCard>
  <AdaptiveCard title="Card without image">
    This card has no image, so layout adjusts automatically.
  </AdaptiveCard>
</AdaptiveGrid>

CSS Feature

The component uses Tailwind's Container Queries plugin with the :has() selector:

// AdaptiveCard uses :has() to detect if it contains an image
className={cn(
  "@container group/card",
  // Layout changes based on content with :has()
  "has-[img]:grid has-[img]:@sm:grid-cols-[140px_1fr]",
  "[&:not(:has(img))]:flex [&:not(:has(img))]:flex-col",
)}

// AdaptiveGrid uses container queries for responsive columns
className={cn(
  "@container",
  "grid-cols-1 @sm:grid-cols-2 @lg:grid-cols-3 @2xl:grid-cols-4",
)}

Props

PropTypeDefaultDescription
imagestring-Optional image URL
titlestring-Card title
minCardWidthnumber280Minimum card width (AdaptiveGrid)
classNamestring-Additional CSS classes