Stack

Vertical layout primitive. Stacks children on the Y axis with a shared gap and optional cross-axis alignment.

Installation

import { Stack } from "@gradeui/ui"

Usage

The default top-level layout inside a page or section. Use Stack instead of hand-rolled flex flex-col gap-* so the vertical rhythm is a variant prop the settings panel can edit.

One
Two
Three

Gap

Vertical spacing between children. Seven steps tied to the spacing scale — none through 2xl.

gap="xs"

1
2
3

gap="md" (default)

1
2
3

gap="xl"

1
2
3

Align

Cross-axis alignment — how each child sits horizontally within the Stack. Default is stretch so children fill the Stack's width.

align="start"

S
M
M

align="center"

S
M
M

align="end"

S
M
M

align="stretch" (default)

S
M
M

asChild

Pass asChild to stamp Stack's layout classes onto an existing semantic element instead of wrapping it in a div. Useful for landmark tags.

<Stack asChild gap="lg">
  <section>
    <Hero>…</Hero>
    <Section>…</Section>
  </section>
</Stack>

Composition

A common pattern — a centred, narrow column for an auth card or marketing copy.

Sign in
Use your work email

Props

PropTypeDefaultDescription
gap"none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl""md"Vertical gap between children.
align"start" | "center" | "end" | "stretch""stretch"Cross-axis (horizontal) alignment of children.
asChildbooleanfalseRender as the single child element via Radix Slot — stamps Stack's layout classes onto an existing semantic tag (e.g. <section>) without nesting a wrapper div.
classNamestringExtra classes merged onto the root element.

When to use

  • As the default top-level layout inside a page's main slot.
  • For any vertical list of sections, cards, or form controls.
  • Prefer Stack over hand-rolled flex flex-col gap-* — the spacing becomes a prop editable in the settings panel.
  • For a horizontal composition, reach for Row instead.

Sidecar

The Markdown sidecar Studio (and the Grade MCP server, when it ships) reads to understand this component — frontmatter, when- to-use guidance, and canonical examples. Authored once at packages/ui/components/ui/stack.md and shipped inside the published @gradeui/ui tarball.

---
name: Stack
import: "@gradeui/ui"
role: layout
props:
  - gap?: "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl" (default "md") — vertical gap between children
  - align?: "start" | "center" | "end" | "stretch" (default "stretch") — cross-axis (horizontal) alignment of children
  - justify?: "start" | "center" | "end" | "between" | "around" | "evenly" (default "start") — main-axis (vertical) distribution. Reach for this on absolute-positioned overlays (`justify="end"` pins children to the bottom) and split footers (`justify="between"`).
  - asChild?: boolean (default false) — render as the child element via Slot, so `<Stack asChild><section>…</section></Stack>` stamps Stack's classes onto the `<section>` rather than nesting a wrapper div
  - className?: string
  - children: React.ReactNode
when_to_use: Default top-level layout inside the main slot when composing two or more stacked regions (hero + content + footer, auth card + subtext, etc.). Prefer Stack over hand-rolled `flex flex-col gap-*` so the vertical rhythm is editable through the settings panel.
composes_with: [Section, Row, Split, Hero, any content component]
aliases: [stack, vstack, vertical, column, vertical layout, v-stack, vertical stack, lazyvstack]
---

```jsx
<Stack gap="lg">
  <Hero>…</Hero>
  <Section>…</Section>
  <Section>…</Section>
</Stack>
```

```jsx
// Narrow centred column for auth / marketing copy.
<Stack gap="md" align="center" className="max-w-md mx-auto">
  <CardTitle>Sign in</CardTitle>
  <Input placeholder="Email" />
  <Input placeholder="Password" type="password" />
  <Button className="w-full">Continue</Button>
</Stack>
```

```jsx
// Hero overlay pinned to the bottom — use `justify="end"`, NOT
// `className="flex flex-col justify-end"`. Stack is already a flex
// column, so `flex flex-col` in className is dead weight.
<Stack justify="end" gap="md" className="absolute inset-0 p-10 max-w-2xl">
  <Badge>Featured</Badge>
  <h1 className="text-5xl font-semibold">Severance</h1>
  <Button>Play</Button>
</Stack>
```

### Anti-patterns

DO NOT add `flex flex-col` to Stack's className — Stack already applies `flex flex-col` as its base. Same for Row + `flex flex-row`. These are the literal definitions of the primitives.

DO NOT reach for `className="justify-end"` (or `justify-between`, etc.) when the new `justify` prop covers it. Inline-Tailwind layout escapes are how scaffolds slowly drift away from the design system — keep them in props so the settings panel can mutate them.