A responsive grid — autofit by default, or a fixed column count.

Last updated

Layout primitive — exempt from Do/Don’t and Content (no misuse or wording surface).

1
2
3
4
Show code
<Grid minItemWidth="10rem" gap={4}>
<div class="rounded-md border border-neutral p-4 text-sm">1</div>
<div class="rounded-md border border-neutral p-4 text-sm">2</div>
<div class="rounded-md border border-neutral p-4 text-sm">3</div>
<div class="rounded-md border border-neutral p-4 text-sm">4</div>
</Grid>

Add

npx @ava-ui/apogee add grid

No Apogee dependencies.

Usage

---
import Grid from '@/components/apogee/Grid/Grid.astro'
---
<Grid>
  <Card />
  <Card />
  <Card />
</Grid>

API

@composable — exposed to Content Editors in AVA. Any other attribute passes through to the root <div>.

Prop Type Default Description
minItemWidth string '16rem' Autofit mode: the smallest a column may get before the count drops. Ignored when cols is set.
cols 1 … 12 | 'auto', responsive — Fixed column count (overrides autofit). { base: 1, md: 3 } for breakpoints.
gap 0 … 6 | 8 | 10 | 12 | 16, responsive 6 Gap size (Tailwind gap-* scale).
colGap / rowGap 0 | 1 | 2 | 3 | 4 | 6 | 8 | 10 | 12 — Gap on one axis.
align 'start' | 'center' | 'end' | 'stretch' — Vertical alignment of items in their cells.
justify 'start' | 'center' | 'end' | 'stretch' — Horizontal alignment of items in their cells.
as string 'div' Tag to render.
class string — Extra classes, merged last.

GridItem

Spans columns or rows; colSpan and rowSpan accept per-breakpoint objects.

Prop Type Default Description
colSpan 1 … 12 | 'full', responsive — Columns to span.
rowSpan 1 … 6, responsive — Rows to span.
colStart 1 … 13 — Column line to start at.
rowStart 1 … 7 — Row line to start at.
as string 'div' Tag to render.
Main (2 of 3 columns from md)
Aside
Footer (full)
Show code
<Grid cols={{ base: 1, md: 3 }} gap={4}>
<GridItem colSpan={{ base: 'full', md: 2 }}>Main</GridItem>
<GridItem>Aside</GridItem>
<GridItem colSpan="full">Footer</GridItem>
</Grid>

Variants

Autofit (default) — columns reflow to the grid’s width, no breakpoints:

A
B
C
D
E
Show code
<Grid minItemWidth="8rem">
<div class="rounded-md border border-neutral p-4 text-sm">A</div>
<div class="rounded-md border border-neutral p-4 text-sm">B</div>
<div class="rounded-md border border-neutral p-4 text-sm">C</div>
<div class="rounded-md border border-neutral p-4 text-sm">D</div>
<div class="rounded-md border border-neutral p-4 text-sm">E</div>
</Grid>

Fixed columns (cols overrides autofit):

1
2
3
Show code
<Grid cols={3}>
<div class="rounded-md border border-neutral p-4 text-sm">1</div>
<div class="rounded-md border border-neutral p-4 text-sm">2</div>
<div class="rounded-md border border-neutral p-4 text-sm">3</div>
</Grid>

Every gap value (two columns, so the gap is easy to compare):

gap=0
gap=0
gap=2
gap=2
gap=4
gap=4
gap=6
gap=6
gap=8
gap=8
gap=10
gap=10
Show code
<div class="flex w-full flex-col gap-6">
<Grid cols={2} gap={0}>
  <div class="rounded-md border border-neutral p-3 text-xs">gap=0</div>
  <div class="rounded-md border border-neutral p-3 text-xs">gap=0</div>
</Grid>
<Grid cols={2} gap={2}>
  <div class="rounded-md border border-neutral p-3 text-xs">gap=2</div>
  <div class="rounded-md border border-neutral p-3 text-xs">gap=2</div>
</Grid>
<Grid cols={2} gap={4}>
  <div class="rounded-md border border-neutral p-3 text-xs">gap=4</div>
  <div class="rounded-md border border-neutral p-3 text-xs">gap=4</div>
</Grid>
<Grid cols={2} gap={6}>
  <div class="rounded-md border border-neutral p-3 text-xs">gap=6</div>
  <div class="rounded-md border border-neutral p-3 text-xs">gap=6</div>
</Grid>
<Grid cols={2} gap={8}>
  <div class="rounded-md border border-neutral p-3 text-xs">gap=8</div>
  <div class="rounded-md border border-neutral p-3 text-xs">gap=8</div>
</Grid>
<Grid cols={2} gap={10}>
  <div class="rounded-md border border-neutral p-3 text-xs">gap=10</div>
  <div class="rounded-md border border-neutral p-3 text-xs">gap=10</div>
</Grid>
</div>

Alignment

align places items vertically in their cells; stretch fills the cell height.

align=“start”

A
B
C

align=“center”

A
B
C

align=“end”

A
B
C

align=“stretch”

A
B
C
Show code
<p class="text-sm text-neutral-faded">align="start"</p>
<Grid cols={3} gap={2} align="start" class="h-20 rounded-md border border-dashed border-neutral p-2"><div class="rounded-sm bg-primary-faded px-2 py-1 text-sm text-primary">A</div><div class="rounded-sm bg-primary-faded px-2 py-1 text-sm text-primary">B</div><div class="rounded-sm bg-primary-faded px-2 py-1 text-sm text-primary">C</div></Grid>
<p class="text-sm text-neutral-faded">align="center"</p>
<Grid cols={3} gap={2} align="center" class="h-20 rounded-md border border-dashed border-neutral p-2"><div class="rounded-sm bg-primary-faded px-2 py-1 text-sm text-primary">A</div><div class="rounded-sm bg-primary-faded px-2 py-1 text-sm text-primary">B</div><div class="rounded-sm bg-primary-faded px-2 py-1 text-sm text-primary">C</div></Grid>
<p class="text-sm text-neutral-faded">align="end"</p>
<Grid cols={3} gap={2} align="end" class="h-20 rounded-md border border-dashed border-neutral p-2"><div class="rounded-sm bg-primary-faded px-2 py-1 text-sm text-primary">A</div><div class="rounded-sm bg-primary-faded px-2 py-1 text-sm text-primary">B</div><div class="rounded-sm bg-primary-faded px-2 py-1 text-sm text-primary">C</div></Grid>
<p class="text-sm text-neutral-faded">align="stretch"</p>
<Grid cols={3} gap={2} align="stretch" class="h-20 rounded-md border border-dashed border-neutral p-2"><div class="rounded-sm bg-primary-faded px-2 py-1 text-sm text-primary">A</div><div class="rounded-sm bg-primary-faded px-2 py-1 text-sm text-primary">B</div><div class="rounded-sm bg-primary-faded px-2 py-1 text-sm text-primary">C</div></Grid>

justify places items horizontally in their cells; stretch fills the cell width.

justify=“start”

A
B
C

justify=“center”

A
B
C

justify=“end”

A
B
C

justify=“stretch”

A
B
C
Show code
<p class="text-sm text-neutral-faded">justify="start"</p>
<Grid cols={3} gap={2} justify="start" class="h-20 rounded-md border border-dashed border-neutral p-2"><div class="rounded-sm bg-primary-faded px-2 py-1 text-sm text-primary">A</div><div class="rounded-sm bg-primary-faded px-2 py-1 text-sm text-primary">B</div><div class="rounded-sm bg-primary-faded px-2 py-1 text-sm text-primary">C</div></Grid>
<p class="text-sm text-neutral-faded">justify="center"</p>
<Grid cols={3} gap={2} justify="center" class="h-20 rounded-md border border-dashed border-neutral p-2"><div class="rounded-sm bg-primary-faded px-2 py-1 text-sm text-primary">A</div><div class="rounded-sm bg-primary-faded px-2 py-1 text-sm text-primary">B</div><div class="rounded-sm bg-primary-faded px-2 py-1 text-sm text-primary">C</div></Grid>
<p class="text-sm text-neutral-faded">justify="end"</p>
<Grid cols={3} gap={2} justify="end" class="h-20 rounded-md border border-dashed border-neutral p-2"><div class="rounded-sm bg-primary-faded px-2 py-1 text-sm text-primary">A</div><div class="rounded-sm bg-primary-faded px-2 py-1 text-sm text-primary">B</div><div class="rounded-sm bg-primary-faded px-2 py-1 text-sm text-primary">C</div></Grid>
<p class="text-sm text-neutral-faded">justify="stretch"</p>
<Grid cols={3} gap={2} justify="stretch" class="h-20 rounded-md border border-dashed border-neutral p-2"><div class="rounded-sm bg-primary-faded px-2 py-1 text-sm text-primary">A</div><div class="rounded-sm bg-primary-faded px-2 py-1 text-sm text-primary">B</div><div class="rounded-sm bg-primary-faded px-2 py-1 text-sm text-primary">C</div></Grid>

Accessibility

Native semantics, no extra ARIA needed. A <div class="grid"> carries no implicit role — if the children form a meaningful list, use a list element (ul/ol) inside or around it as appropriate.

Tokens

No CSS custom properties. Column width comes from an inline grid-template-columns (computed from minItemWidth or cols); gap comes from Tailwind’s built-in gap-* spacing scale, not a bespoke token.