Grid

With no columns, a grid auto-fits as many tracks of at least min as the space allows, and each one shares the leftover evenly. That is the behaviour a card list wants, and it needs no breakpoints: resize this page and the demos below reflow on their own.

Auto-fit

The default. Tracks are at least 16rem wide.

Routing

Data loading

Assets

Images

Islands

Search

grid(
  ...['Routing', 'Data loading', 'Assets', 'Images', 'Islands', 'Search'].map((name) =>
    card({ variant: 'flat' }, cardBody(text({ variant: 'small' }, name))),
  ),
)

Track width

min sets how narrow a track may get before the grid drops to fewer columns. Smaller means more columns.

sm

md

lg

xl

2xl

3xl

4xl

5xl

grid({ min: '9rem' },
  ...['sm', 'md', 'lg', 'xl', '2xl', '3xl', '4xl', '5xl'].map((name) =>
    card({ variant: 'flat' }, cardBody(text({ variant: 'small', align: 'center' }, name))),
  ),
)

A fixed number of columns

Pass a number when the count should not change with the viewport. Each track is an equal share.

One

Two

Three

grid({ columns: 3 },
  ...['One', 'Two', 'Three'].map((name) =>
    card({ variant: 'flat' }, cardBody(text({ variant: 'small', align: 'center' }, name))),
  ),
)

A custom template

A string is passed straight through as grid-template-columns, for a sidebar-and-content split or anything else CSS grid can express.

Sidebar

Content, taking the rest of the row.

grid({ columns: '12rem 1fr', gap: 'lg' },
  card({ variant: 'flat' }, cardBody(text({ variant: 'small' }, 'Sidebar'))),
  card({ variant: 'flat' }, cardBody(text({ variant: 'small' }, 'Content, taking the rest of the row.'))),
)

Gap and alignment

Short

A taller card, with two lines of text in it, to show what align does to its shorter neighbours.

Short

grid({ min: '10rem', gap: 'xl', align: 'center' },
  card({ variant: 'flat' }, cardBody(text({ variant: 'small' }, 'Short'))),
  card({ variant: 'flat' }, cardBody(text({ variant: 'small' }, 'A taller card, with two lines of text in it, to show what align does to its shorter neighbours.'))),
  card({ variant: 'flat' }, cardBody(text({ variant: 'small' }, 'Short'))),
)

Props

PropTypeDefaultDescription
columnsnumber | stringA fixed track count, or a raw grid-template-columns value. Omit for auto-fit.
minstring'16rem'Minimum track width when auto-fitting.
gapSpace'md'Space between tracks and rows.
alignstring'stretch'Any align-items value.
asstring'div'Element to render.

A track never gets wider than the grid itself, even when min is larger than the space available — so a 16rem minimum does not cause a horizontal scrollbar on a 320px phone.