# Stack

> A flex row or column with a spacing token for the gap — the layout primitive most pages are built from.

Stack puts space between things. It is a flex container with one job, and it is the answer to most "how do I space these out" questions — vertically by default, horizontally with `direction: 'row'`.

Gaps come from the spacing scale, so the rhythm of a page stays consistent without anyone picking pixel values.

## Basic stack

```javascript
stack({ gap: 'md' },
  card(cardBody('First')),
  card(cardBody('Second')),
  card(cardBody('Third')),
)
```

## Direction

```javascript
stack({ direction: 'row', gap: 'md' },
  button('One'),
  button({ variant: 'outline' }, 'Two'),
  button({ variant: 'outline' }, 'Three'),
)
```

## Gap

A token name (`'xs'` … `'3xl'`), a number of spacing units, or a raw CSS length.

```javascript
stack({ gap: 'lg' },
  stack({ direction: 'row', gap: 'xs' }, chip('xs'), chip('xs'), chip('xs')),
  stack({ direction: 'row', gap: 'md' }, chip('md'), chip('md'), chip('md')),
  stack({ direction: 'row', gap: 6 }, chip('6 units'), chip('6 units')),
  stack({ direction: 'row', gap: '3rem' }, chip('3rem'), chip('3rem')),
)
```

## Alignment

`align` and `justify` take raw flexbox values, so anything CSS understands works.

```javascript
stack({ gap: 'md' },
  stack({ direction: 'row', gap: 'sm', justify: 'space-between', style: 'background: var(--su-surface-2); padding: 0.6rem; border-radius: 0.5rem' },
    chip('start'),
    chip('end'),
  ),
  stack({ direction: 'row', gap: 'sm', justify: 'center', align: 'center', style: 'background: var(--su-surface-2); padding: 0.6rem; border-radius: 0.5rem' },
    button({ size: 'sm' }, 'Centred'),
    chip('and aligned'),
  ),
)
```

## Wrapping

A row of chips or buttons that might not fit needs `wrap` — without it they squash instead of moving to the next line.

```javascript
stack({ direction: 'row', gap: 'sm', wrap: true },
  ...['routing', 'data', 'islands', 'images', 'pagefind', 'lighthouse', 'sitemap', 'rss'].map(
    (name) => chip({ color: 'neutral' }, name),
  ),
)
```

## Inline

`inline` makes the stack an `inline-flex`, so it sits in a line of text rather than taking the full width.

```javascript
text(
  'Built with ',
  stack({ direction: 'row', gap: 'xs', inline: true, align: 'center' },
    chip({ color: 'primary', size: 'sm' }, 'sitelo'),
    chip({ color: 'neutral', size: 'sm' }, 'vite'),
  ),
  ' and nothing else.',
)
```

## As another element

```javascript
stack({ as: 'nav', direction: 'row', gap: 'sm' },
  navLink({ href: '/docs' }, 'Docs'),
  navLink({ href: '/ui', current: true }, 'UI'),
  navLink({ href: '/examples' }, 'Examples'),
)
```

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `direction` | `'row' \| 'column'` | `'column'` | Main axis. |
| `gap` | `Space` | `'md'` | Space between children. |
| `align` | `string` | `'stretch'` | Any align-items value. |
| `justify` | `string` | `'flex-start'` | Any justify-content value. |
| `wrap` | `boolean \| string` | `false` | true means wrap; a string is passed through as flex-wrap. |
| `inline` | `boolean` | `false` | Renders as inline-flex. |
| `as` | `string` | `'div'` | Element to render, e.g. nav or ul. |
