Skip to main content
Pricing

Stack

Free

A 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

Direction
Item 1
Item 2
Item 3

Variants

VariantDescriptionWhen to use
VerticalStacks children top-to-bottom with a configurable gap.Use for form fields, card content sections, page sections, and any vertical flow of elements.
HorizontalLays children out left-to-right with a configurable gap.Use for button groups, tag rows, inline elements, or avatar stacks.

Usage Guidelines

Do

Use Stack as the default layout container instead of adding margins to individual children.

Don't

Add margin to direct children of a Stack — the gap prop handles all spacing.

Do

Choose gap values from the spacing scale (4, 8, 12, 16, 24, 32, 40, 48) for consistency.

Don't

Use Stack for complex two-dimensional layouts — use Grid System instead.

Do

Use the responsive variant to handle mobile layouts without media query overrides.

Don't

Reorder children visually with CSS order without updating the DOM order.

Do

Nest Stacks freely — a vertical Stack of horizontal Stacks is a common pattern.

Don't

Code

HTML
<!-- 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>
CSS Custom Properties
.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));
}
React
// 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

TokenValue (dark)Value (light)CSS property
--lex-stack-gapgap
--lex-stack-alignalign

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.

Keyboard Interactions

TabMoves focus through interactive children in DOM order.