Skip to main content
BM

Stack

Vertical or horizontal flow with gaps from the spacing scale.

View source on GitHub

StackExample.tsx
import { Button } from "@/components/Button";
import { Stack } from "@/components/Stack";

export function StackExample() {
  return (
    <Stack direction="horizontal" gap="sm">
      <Button variant="primary">Publish</Button>
      <Button>Preview</Button>
      <Button variant="ghost">Discard</Button>
    </Stack>
  );
}

Examples

Vertical (default), gaps none to xl

gap noneB
gap xsB
gap smB
gap mdB
gap lgB
gap xlB

Horizontal, gaps none to xl

gap noneBC
gap xsBC
gap smBC
gap mdBC
gap lgBC
gap xlBC

Align

align startTwo
lines
align centerTwo
lines
align endTwo
lines
align stretchTwo
lines
align baselineTwo
lines

Justify

justify startB
justify centerB
justify endB
justify betweenB

Vertical alignment

Wrapping by default

  • React
  • TypeScript
  • AWS CDK
  • Vite
  • Playwright
  • CloudFront

One line

Project

Row and column gaps

  • React
  • TypeScript
  • AWS CDK
  • Vite
  • Playwright
  • CloudFront

Semantics

Contact preference

Props

Any native prop not listed here goes to the root element unchanged.

A vertical Stack stretches its children across its width, so an inline-level child such as a Button spans the full width unless align is set. baseline aligns only in horizontal Stacks. justify and a vertical wrap need a block size.

Stack props
PropTypeDefaultDescription
as"div" | "section" | "article" | "aside" | "header" | "footer" | "nav" | "main" | "ul" | "ol" | "li" | "form" | "fieldset""div"The root element. Lists keep their semantics without markers.
direction"vertical" | "horizontal""vertical"No reverse directions, so reading order is visual order.
gap"none" | "xs" | "sm" | "md" | "lg" | "xl""md"Sets the row gap (space.stack.*) and the column gap (space.inline.*).
rowGap"none" | "xs" | "sm" | "md" | "lg" | "xl"gapBetween rows (space.stack.*): items in a vertical Stack, wrapped lines in a horizontal one.
columnGap"none" | "xs" | "sm" | "md" | "lg" | "xl"gapBetween columns (space.inline.*): items in a horizontal Stack, wrapped columns in a vertical one.
align"start" | "center" | "end" | "stretch" | "baseline"—Cross-axis alignment.
justify"start" | "center" | "end" | "between"—Main-axis distribution.
wrapbooleantrue when horizontalWrap items onto new lines. wrap={false} keeps a horizontal Stack on one line.

Component tokens

None. Every value is chosen by a prop from a semantic scale.

Accessibility

  • A div by default, or any element from a closed set (section, nav, ul, ol, form…).
  • As ul or ol, markers go but list semantics stay (role="list" is restated for Safari).
  • Spacing uses gap only, and DOM order is visual order.
  • Horizontal Stacks wrap by default, so rows reflow at narrow widths and high zoom (WCAG 1.4.10).
  • As a fieldset, the legend is still the group's name and is spaced like the other items.