Stack
FreeA one-dimensional flex layout primitive for arranging children vertically or horizontally with consistent gap spacing. Replaces ad-hoc flexbox wrappers with a declarative API for direction, gap, alignment, and wrapping. The most commonly used layout component in any interface.
4 variants
Variants
| Variant | Description | When to use |
|---|---|---|
| Vertical | Stacks children top-to-bottom with a configurable gap. | Use for form fields, card content sections, page sections, and any vertical flow of elements. |
| Horizontal | Lays children out left-to-right with a configurable gap. | Use for button groups, tag rows, inline elements, or avatar stacks. |
Usage Guidelines
Use Stack as the default layout container instead of adding margins to individual children.
Add margin to direct children of a Stack — the gap prop handles all spacing.
Choose gap values from the spacing scale (4, 8, 12, 16, 24, 32, 40, 48) for consistency.
Use Stack for complex two-dimensional layouts — use Grid System instead.
Use the responsive variant to handle mobile layouts without media query overrides.
Reorder children visually with CSS order without updating the DOM order.
Nest Stacks freely — a vertical Stack of horizontal Stacks is a common pattern.
Code
<!-- Vertical stack -->
<div class="lex-stack lex-stack--vertical"
style="--lex-layout-gap: var(--lex-space-16);">
<label class="lex-label" for="name-field">Full name</label>
<input class="lex-input" id="name-field" type="text"
placeholder="Enter your full name" />
<span class="lex-hint">Enter your legal name as it appears on your ID.</span>
</div>
<!-- Horizontal stack -->
<div class="lex-stack lex-stack--horizontal"
style="--lex-layout-gap: var(--lex-space-8);">
<button class="lex-button lex-button--primary lex-button--md">
Save changes
</button>
<button class="lex-button lex-button--secondary lex-button--md">
Cancel
</button>
</div>
<!-- Wrapping horizontal stack -->
<div class="lex-stack lex-stack--horizontal lex-stack--wrap"
style="--lex-layout-gap: var(--lex-space-8);">
<span class="lex-tag">React</span>
<span class="lex-tag">TypeScript</span>
<span class="lex-tag">Node.js</span>
<span class="lex-tag">GraphQL</span>
<span class="lex-tag">Tailwind</span>
</div>
<!-- Responsive stack: horizontal on desktop, vertical on mobile -->
<div class="lex-stack lex-stack--horizontal lex-stack--responsive"
style="--lex-layout-gap: var(--lex-space-24);">
<div class="lex-card">Plan A</div>
<div class="lex-card">Plan B</div>
<div class="lex-card">Plan C</div>
</div>.lex-stack {
display: flex;
gap: var(--lex-layout-gap, var(--lex-space-16));
}
.lex-stack--vertical {
flex-direction: column;
}
.lex-stack--horizontal {
flex-direction: row;
align-items: center;
}
.lex-stack--wrap {
flex-wrap: wrap;
}
.lex-stack--align-start { align-items: flex-start; }
.lex-stack--align-center { align-items: center; }
.lex-stack--align-end { align-items: flex-end; }
.lex-stack--align-stretch { align-items: stretch; }
.lex-stack--justify-between { justify-content: space-between; }
.lex-stack--justify-center { justify-content: center; }
.lex-stack--justify-end { justify-content: flex-end; }
/* Responsive: horizontal → vertical below breakpoint */
@media (max-width: 640px) {
.lex-stack--responsive {
flex-direction: column;
}
}
/* With dividers between children */
.lex-stack--divided > * + * {
border-top: 1px solid var(--lex-border-default);
padding-top: var(--lex-layout-gap, var(--lex-space-16));
}
.lex-stack--horizontal.lex-stack--divided > * + * {
border-top: none;
border-left: 1px solid var(--lex-border-default);
padding-top: 0;
padding-left: var(--lex-layout-gap, var(--lex-space-16));
}// Using Lexicon CSS classes with React
export function FormSection() {
return (
<Stack gap={16}>
<InputField label="Full name" hint="Enter your legal name." />
<InputField label="Email" type="email" />
<Stack direction="horizontal" gap={8}>
<Button variant="primary">Save changes</Button>
<Button variant="secondary">Cancel</Button>
</Stack>
</Stack>
);
}
export function TagCloud({ tags }: { tags: string[] }) {
return (
<Stack direction="horizontal" gap={8} wrap>
{tags.map((tag) => (
<Tag key={tag}>{tag}</Tag>
))}
</Stack>
);
}
export function PricingCards() {
return (
<Stack direction="horizontal" gap={24} responsive>
<PricingCard plan="Starter" price="$0" />
<PricingCard plan="Pro" price="$29" />
<PricingCard plan="Enterprise" price="Custom" />
</Stack>
);
}Design Tokens
| Token | Value (dark) | Value (light) | CSS property |
|---|---|---|---|
| --lex-stack-gap | — | — | gap |
| --lex-stack-align | — | — | align |
Accessibility
- Visual order must match DOM order — never use CSS order to rearrange children.
- Stack is a purely visual layout component — it adds no ARIA roles or semantic meaning.
- When using Stack for navigation items, wrap children in a <nav> with aria-label.
- Gap spacing should be consistent to meet cognitive accessibility guidelines.