Stack
Arrange related content vertically or horizontally with consistent spacing between groups, headings and sections.
tight8 px
the lines of one thing
group16 px
the things of one group
title24 px
a title and its text
block48 px
the blocks of a page
section96 px
the sections of a page
<script setup lang="ts">import { UiStack } from 'grani' interface Step { gap: 'tight' | 'group' | 'title' | 'block' | 'section' px: number use: string} const steps: Step[] = [ { gap: 'tight', px: 8, use: 'the lines of one thing' }, { gap: 'group', px: 16, use: 'the things of one group' }, { gap: 'title', px: 24, use: 'a title and its text' }, { gap: 'block', px: 48, use: 'the blocks of a page' }, { gap: 'section', px: 96, use: 'the sections of a page' },]</script> <template> <div class="flex w-full flex-wrap items-start gap-8"> <div v-for="step in steps" :key="step.gap" class="flex w-32 flex-col gap-2"> <p class="text-sm text-fg"> <span class="font-medium">{{ step.gap }}</span> <span class="text-fg-muted"> {{ step.px }} px</span> </p> <UiStack :gap="step.gap"> <div class="h-6 rounded-control bg-surface-muted" /> <div class="h-6 rounded-control bg-surface-muted" /> </UiStack> <p class="text-xs text-fg-muted">{{ step.use }}</p> </div> </div></template>
Also called vertical stack, vstack, spacing scale.
Usage
<UiStack>…</UiStack> With GraniResolver in the Vite config, a template needs no import: set it up once.
API
| Name · type | Default | Description |
|---|---|---|
| gapblock | title | group | section | tight= "group" | "group" | The relation between the children, a step of the scale: tight 8, group 16, title 24, block 48, section 96 px. |
| directioncolumn | row= "column" | "column" | column stacks the children; row lines them up on one line. |
| alignstart | center | end | stretch | Where the children stand across the stack. Unset, a column stretches them to its width and a row centers them on the line. | |
| asdiv | form | section | ul | li= "div" | "div" | The element: div by default; section, ul, form or li when the stack is one. |
Anything else lands on the root element: native attributes, aria-*, data-testid.
When to use another component
| When you need | Take |
|---|---|
| Text on the left and a thing on the right | List item |
| A table | Table |
| The toolbar row | Table toolbar owns it |
| Buttons joined into one capsule | Button group |
| A grid of columns | The page lays it out itself |