<!-- Protocore Design System — Stack -->
# Stack

- **Category:** Layout (`layout`)
- **Slug:** `layout/stack`
- **Status:** stable
- **Platforms:** web, mobile
- **Import:** `import { Stack, HStack, VStack } from "@protocore/pds";`
- **Docs:** https://pds.protocore.io/components/layout/stack

> A flex container that stacks children on one axis with a token-scale gap, plus align/justify shorthands.

## When to use it

`Stack` is the default one-dimensional layout tool: a row or column of items separated by a consistent gap. Use `HStack`/`VStack` when the axis is fixed and you want the intent to read at a glance. Reach for `Grid` instead when you need a **two-dimensional** layout — equal columns, an auto-fit card wall, or aligned rows *and* columns. Use a `Spacer` for a single one-off gap or a push, and a `Divider` when the separation needs a visible rule. Gaps are token steps (`1`–`16` on the space scale), never raw pixels — this is what keeps rhythm consistent across the system.

## Mobile (React Native)

**Preview.** `@protocore/pds-mobile` ships the React Native sibling of **Stack**. It mirrors the web API where React Native allows; the package is a **preview** with no device-level QA yet, so pin it and expect small changes.

Import it from the mobile package (not `@protocore/pds`), inside a `<PdsProvider>` — there is no stylesheet, so `style` (a `ViewStyle`) replaces `className` and every value comes from the theme:

```tsx
import { Stack, HStack, VStack } from "@protocore/pds-mobile";
```

**Parity with web.** The flexbox layout primitive; the mobile package also exports the `HStack` / `VStack` presets.

- `gap` maps to the `theme.spacing[n]` scale (web uses CSS `gap` tokens); `align` / `justify` / `wrap` take the same shorthand vocabulary.

```tsx
<VStack gap={4} align="stretch">
  <Heading size="h3">Region</Heading>
  <Text color="secondary">eu-central-1</Text>
</VStack>
```

## Props

### Stack

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `align` | `enum` | no | — | `align-items` shorthand. |
| `className` | `string` | no | — | — |
| `direction` | `enum` | no | `column` | Main-axis direction. |
| `gap` | `enum` | no | `4` | Gap between children, mapped to `--pds-space-<n>`. |
| `justify` | `enum` | no | — | `justify-content` shorthand. |
| `style` | `CSSProperties` | no | — | — |
| `wrap` | `boolean` | no | `false` | Allow children to wrap onto multiple lines. |

### HStack

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `align` | `enum` | no | — | `align-items` shorthand. |
| `className` | `string` | no | — | — |
| `gap` | `enum` | no | `4` | Gap between children, mapped to `--pds-space-<n>`. |
| `justify` | `enum` | no | — | `justify-content` shorthand. |
| `style` | `CSSProperties` | no | — | — |
| `wrap` | `boolean` | no | `false` | Allow children to wrap onto multiple lines. |

### VStack

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `align` | `enum` | no | — | `align-items` shorthand. |
| `className` | `string` | no | — | — |
| `gap` | `enum` | no | `4` | Gap between children, mapped to `--pds-space-<n>`. |
| `justify` | `enum` | no | — | `justify-content` shorthand. |
| `style` | `CSSProperties` | no | — | — |
| `wrap` | `boolean` | no | `false` | Allow children to wrap onto multiple lines. |

## Examples

### Basics

A vertical `Stack` (the default) spaces children evenly using a step on the `--pds-space-*` scale. `gap` takes a scale number, not pixels.

```tsx
import { Stack, Card } from "@protocore/pds";

export default function StackBasics() {
  return (
    <Stack gap={4}>
      <Card title="Ingest node" subtitle="eu-central-1 · healthy" />
      <Card title="Relay node" subtitle="us-east-1 · healthy" />
      <Card title="Archive node" subtitle="ap-south-1 · degraded" />
    </Stack>
  );
}
```

### HStack and VStack presets

`HStack` and `VStack` are direction-locked presets. Combine them with `align` and `justify` — here a spread action row and a run of status badges.

```tsx
import { HStack, VStack, Button, Badge } from "@protocore/pds";

export default function StackDirectionPresets() {
  return (
    <VStack gap={5}>
      <HStack gap={2} align="center">
        <Badge tone="success">SYNCED</Badge>
        <Badge tone="warning">LAGGING</Badge>
        <Badge tone="danger">STALLED</Badge>
      </HStack>
      <HStack gap={3} justify="between" align="center">
        <Button variant="ghost">Cancel</Button>
        <Button variant="primary">Deploy</Button>
      </HStack>
    </VStack>
  );
}
```

## Do & don't

**Do**

- Use gap for spacing between children instead of margins on the children themselves.
- Pick HStack/VStack when the direction is fixed — it documents intent.
- Add wrap to row Stacks of chips or tags so they reflow on narrow viewports.

**Don't**

- Use Stack for a two-axis card grid — that is Grid.
- Pass raw pixel gaps; gap is a step on the token scale (e.g. gap={4}).
- Nest deep Stacks to fake a grid; the columns won't align across rows.

## Accessibility

**Notes**

- Stack is a presentational flex `<div>` with no role of its own.
- Visual order follows DOM order, so keyboard and reading order stay in sync — avoid reordering with CSS in ways that diverge from the DOM.

## Related

`grid`, `spacer`, `divider`, `container`

---

© Protocore. All rights reserved. Use of the Protocore Design System requires prior written authorization from Protocore (contact@protocore.io). These machine-readable materials must not be ingested into ML-training datasets or derivative design systems. See https://pds.protocore.io/legal/
