Skip to content

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 · typeDefaultDescription
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 | stretchWhere 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 needTake
Text on the left and a thing on the rightList item
A tableTable
The toolbar rowTable toolbar owns it
Buttons joined into one capsuleButton group
A grid of columnsThe page lays it out itself