Responsive Grid

A content-agnostic responsive grid container. CSS Grid tracks are sized via the auto-fit + minmax pattern, so the grid reflows without media queries. Pair it with any card, image, or tile component to get a responsive surface.

01
02
03
04
05
06
07
08
09
Customize
Items
9
Layout
10rem
3
Shape

Installation

npx shadcn@latest add https://craftbits.dev/r/responsive-grid.json

Usage

import { ResponsiveGrid } from "@craft-bits/core";
 
<ResponsiveGrid minColumnWidth="16rem" gap={4}>
  {items.map((item) => (
    <Card key={item.id} {...item} />
  ))}
</ResponsiveGrid>

Lock every item to a square so the layout reads as a uniform mosaic:

<ResponsiveGrid minColumnWidth="12rem" gap={3} aspectRatio="1">
  {images.map((image) => (
    <img key={image.id} src={image.src} alt={image.alt} />
  ))}
</ResponsiveGrid>

Understanding the component

  1. Pure layout. The component only owns the wrapping div's grid template and gap. Children render verbatim as direct grid items.
  2. Responsive without media queries. Tracks use the auto-fit minmax pattern; as the viewport shrinks, tracks collapse and items reflow.
  3. Aspect ratio is opt-in. Pass an aspectRatio string and every immediate child receives that ratio via a CSS variable, so the grid reads as a uniform tile field. Omit it and items size to their own content.
  4. No hidden image handling. Unlike the source, this grid is content-agnostic. Use any component as a child.

Variants

Three tight columns with generous gap:

<ResponsiveGrid minColumnWidth="14rem" gap="1.25rem">
  {children}
</ResponsiveGrid>

Square tiles for a gallery surface:

<ResponsiveGrid minColumnWidth="10rem" gap={3} aspectRatio="1">
  {children}
</ResponsiveGrid>

Wide cinematic tiles:

<ResponsiveGrid minColumnWidth="18rem" gap={4} aspectRatio="16/9">
  {children}
</ResponsiveGrid>

Props

PropTypeDefaultDescription
minColumnWidthstring'16rem'Floor width for each auto-fit track. Accepts any CSS length.
gapnumber | string4Numbers map to Tailwind spacing units (4 = 1rem); strings are used verbatim.
aspectRatiostringOptional CSS aspect-ratio applied to every immediate child (e.g. '1', '16/9').
classNamestringMerged onto the grid root via cn().

Accessibility

  • The grid is a plain <div> by default. When the items form a semantic list, pair role="list" on the root with role="listitem" on each child so assistive tech announces the relationship.
  • Focus order follows DOM order. Items render in array order, so reorder children to reorder tab focus.
  • The component never animates layout, so no reduced-motion fallback is required.

Credits

  • Extracted from: terminal-dreams (src/components/frontend-design/sdp-image-gallery/ui/ResponsiveGrid.tsx). The source coupled the grid to a project-specific GalleryImage type, lightbox callbacks, retry / placeholder / lazy-load state, and an embedded Picsum image renderer. craft-bits keeps the responsive auto-fit layout but reshapes the API to a content-agnostic container that accepts arbitrary children, exposes minColumnWidth / gap / aspectRatio, and strips every image-specific concern.