Skip to content
The Membrane Palette
Layoutstable

Layout

Container, Stack, Cluster, Grid, Section and Surface primitives that compose any page without custom layout CSS.

Examples

Stack and cluster

Workshop

Designing with the membrane

Pedagogy AI systems 90 min
HTML for “Stack and cluster”
<div class="mp-stack" data-gap="3">
  <p class="mp-card__overline">Workshop</p>
  <h3 class="type-h3">Designing with the membrane</h3>
  <div class="mp-cluster" data-gap="2">
    <span class="mp-tag" data-tone="human">Pedagogy</span>
    <span class="mp-tag" data-tone="digital">AI systems</span>
    <span class="mp-tag">90 min</span>
  </div>
</div>

Responsive grid

One

Two

Three

HTML for “Responsive grid”
<div class="mp-grid" data-min="sm" data-gap="4">
  <div class="mp-card" data-variant="flat"><p class="mp-card__body">One</p></div>
  <div class="mp-card" data-variant="flat"><p class="mp-card__body">Two</p></div>
  <div class="mp-card" data-variant="flat"><p class="mp-card__body">Three</p></div>
</div>

Cluster justification and alignment

Workshops

See all workshops
centered row
HTML for “Cluster justification and alignment”
<div class="mp-stack" data-gap="3">
  <div class="mp-cluster" data-justify="between" data-align="baseline">
    <h3 class="type-h3">Workshops</h3>
    <a class="mp-link" data-variant="standalone" href="#components">See all<span class="mp-visually-hidden"> workshops</span></a>
  </div>
  <div class="mp-cluster" data-justify="center">
    <span class="mp-tag">centered</span>
    <span class="mp-tag">row</span>
  </div>
  <div class="mp-cluster" data-justify="end" data-align="start">
    <button class="mp-button" type="button" data-variant="ghost">Cancel</button>
    <button class="mp-button" type="button">Save</button>
  </div>
</div>

Surface tones

Default — --color-bg-primary

Secondary — cards, alternating bands

Elevated — dialogs, popovers (lighter in dark mode)

HTML for “Surface tones”
<div class="mp-grid" data-min="sm" data-gap="4">
  <div class="mp-section mp-surface" data-size="sm"><div class="mp-container"><p class="type-small">Default — <code class="mp-code">--color-bg-primary</code></p></div></div>
  <div class="mp-section mp-surface" data-size="sm" data-tone="secondary"><div class="mp-container"><p class="type-small">Secondary — cards, alternating bands</p></div></div>
  <div class="mp-section mp-surface" data-size="sm" data-tone="elevated"><div class="mp-container"><p class="type-small">Elevated — dialogs, popovers (lighter in dark mode)</p></div></div>
</div>

Dark band inside a light page

Every token inside this section resolves to its dark value, because data-theme="dark" sets color-scheme for the subtree.

HTML for “Dark band inside a light page”
<section class="mp-section mp-surface" data-size="sm" data-theme="dark">
  <div class="mp-container" data-size="sm">
    <p class="type-body">Every token inside this section resolves to its dark value, because <code class="mp-code">data-theme="dark"</code> sets <code class="mp-code">color-scheme</code> for the subtree.</p>
  </div>
</section>

Guidance

Six small primitives cover almost every arrangement on a page. Gaps are always a step on the spacing scale (data-gap="4" → --space-4), so rhythm stays on the 4px grid without anyone typing a pixel value.

PrimitiveDoesDefault gap
.mp-containerCenters content at a max width with fluid side margins (--site-margin)—
.mp-stackVertical flow--space-4
.mp-clusterHorizontal row that wraps (buttons, tags, metadata)--space-3
.mp-gridResponsive auto-fit columns, no breakpoints needed--space-6
.mp-sectionVertical padding for a page band--space-20
.mp-surfacePaints --color-bg-primary + --color-text-primary (needed when you flip a subtree with data-theme)—

.mp-visually-hidden hides content visually while keeping it available to screen readers.

data-gap, data-min (grid column minimum: sm 12rem, default 16rem, lg 22rem) and data-size (container sm/md/lg → --container-*; section sm/lg → --space-12/--space-32) are scales that map 1:1 onto tokens, so they aren't each demonstrated below.

When to use

  • Any page or panel layout. Reach for these before writing display: flex by hand.
  • .mp-grid for card collections: columns appear and collapse based on available width, so it works in sidebars and full-width bands alike.

When not to use

  • Complex, named-area layouts (dashboards with a fixed sidebar) — write a CSS Grid with grid-template-areas, still using --space-* for gaps.

Accessibility

  • Layout primitives change visual order only through normal document flow — they never reorder content, so reading order and focus order stay aligned.
  • .mp-visually-hidden content is announced but invisible; it becomes visible if it (or a descendant) receives focus.

API

Layout classes
ClassKind
.mp-containerroot
.mp-stackroot
.mp-clusterroot
.mp-gridroot
.mp-sectionroot
.mp-surfaceroot
.mp-visually-hiddenroot
Layout attributes
AttributeValues
data-sizesm · md · lg
data-justifybetween · center · end
data-alignstart · baseline
data-minsm · lg
data-gap0 · 1 · 2 · 3 · 4 · 5 · 6 · 8 · 10 · 12 · 16
data-tonesecondary · elevated

States styled: :active :focus-within. Set the native attribute or ARIA state; there are no state classes.

Layout component tokens
TokenDefaultLight · dark
--mp-container-maxvar(--container-xl)—
--mp-gapvar(--space-4)—
--mp-grid-min16rem—
--mp-section-spacevar(--space-20)—

Design tokens consumed: --color-bg-elevated --color-bg-primary --color-bg-secondary --color-text-primary --container-lg --container-md --container-sm --container-xl --site-margin --space-1 --space-10 --space-12 --space-16 --space-2 --space-20 --space-3 --space-32 --space-4 --space-5 --space-6 --space-8

Source