A grid fixes the number of columns across a region and lets the children fill them. It is the
layout a card deck, a feature list, a pricing table or a dashboard is built on: the count is the
design decision, and each cell wraps onto the next row without being told where it goes.

Two things separate it from its siblings. `Stack` arranges one axis, a row or a column in the
order you write it, while a grid is two-dimensional, so the count across is stated once and the
rows follow. And `Split` is only ever two panes; a grid is for the case where there are many cells
and they are interchangeable.

```tsx demo="layouts/grid-preview"
```

## Usage

```tsx
import { Grid } from "@asheeui/web";

<Grid columns={1} columnsMd={2} columnsLg={3} gap="lg">
  <Card title="Inbox" description="12 unread" />
  <Card title="Sent" description="348 this month" />
  <Card title="Drafts" description="3 unfinished" />
</Grid>
```

`gap` is a token from the shared spacing scale rather than a number of pixels, so a grid and the
stack inside one of its cells keep the same rhythm.

## The column scale

`columns` is one of `1`, `2`, `3`, `4`, `6` or `12`. There is no arbitrary count, because every
column class has to be a complete literal the stylesheet can see; the larger counts are for a
layout that needs the finer division, not for spanning a cell across several tracks, with
`columns={12}` each child still takes exactly one of the twelve.

The direction is mobile-first. `columns` is the count at the narrowest viewport, `columnsMd` takes
over from the `md` breakpoint and `columnsLg` from `lg`, and a breakpoint you leave unstated
inherits the count below it rather than forcing one. A grid that never changes shape states
`columns` alone; a grid that changes twice states all three.

```tsx demo="layouts/grid-columns"
```

Because the breakpoints are min-width, `columnsLg` has the last word on a wide screen even when
`columnsMd` is also stated. Read the three props as one sentence from narrow to wide rather than
as three independent overrides.

## A row that does not fill

Cells are placed in the order they are written, left to right and then onto the next row. When the
children do not divide evenly by the column count the last row is simply short: each cell keeps
the width of the track it sits in, and the remaining tracks stay empty instead of stretching a
cell to fill them.

That is usually what a deck of cards wants, and it is worth checking at each breakpoint: five
cards are a tidy 3 + 2 at `lg` and a wasteful 2 + 2 + 1 at `md`, so the count is the thing to
tune, not the children.

```tsx demo="layouts/grid-row-fill"
```

`align` decides the cross axis for every cell. The default, `stretch`, makes the cells in a row
share its height, which is what a row of cards with different amounts of text needs; `start`,
`center` and `end` let each cell keep its own height and align it within the row instead.

## Props

```props Grid
```

`columns`, `gap` and `align` are registered by the component as `1`, `md` and `stretch`, so each
resolves from the instance, then `components.grid`, then that value. `columnsMd` and `columnsLg`
are deliberately left out of both the registered defaults and the fallback: an unstated breakpoint
has to inherit the count below it, and a registered value would replace that inheritance with a
number the application never asked for. A page with no configuration therefore gets a
single-column grid with a `md` gap, and `components.grid` states the application's count once for
every deck in the product.

## Accessibility

- A grid adds no role and no ARIA attributes. It changes presentation only, so the cells are read
  by a screen reader and reached with <kbd>Tab</kbd> in the order they are written, the visual
  arrangement cannot reorder them.
- `as` renders the element you name, so a grid whose cells are list items states `as="ul"` and
  receives `li` children. That gives the deck list semantics, how many items, and the position
  within them, rather than a run of unrelated boxes.
- `gap` is spacing on the container, not a wrapper element between the cells, so nothing extra
  sits in the reading order and no `tabindex` is introduced.
- Alignment is layout: `stretch` makes the cards in a row match heights and says nothing about
  their headings, so keep each card's own `titleAs` in step with the page's outline.

Gaps, width tokens and the axis words are the layout family's shared vocabulary rather than a
grid-only set, see [Layout and spacing](/concepts/layout-and-spacing).

## Native

`@asheeui/native` exports the same `Grid` with the same `columns`, `columnsMd`, `columnsLg` and
`gap`, and the same inheritance rule. What differs is the mechanism: a device has no media query,
so the grid asks `useBreakpoint` what the window has reached and places the cells as a wrapped row
of fixed-basis children. That mechanism states its cell widths as four counts, so `6` and `12` are
expressed on the web only and fall back to a single column on a device; keep to `1` to `4` in a
grid that has to render on both. See [React Native](/platforms/native).

## Related

```related stack, split, card
```
