Mosaic Mosaic 0.9.4

0002 · block composition

**Status:** Accepted **Date:** 2026-05-19

Status: Accepted Date: 2026-05-19

Context

Real pages on real sites are not one body of text. They are a stack of distinct sections — a hero, a mission statement, a featured-story grid, an upcoming-events block, a CTA. Each section has its own content, its own attributes, and is often reused across pages.

A Mosaic-native pattern needs to support:

  1. Reuse — the same section block appearing on multiple pages.
  2. Reordering — changing the visual stack without touching markup.
  3. Per-section attributes — alignment, theme, variant, etc.
  4. Future visual editing — a drag-and-drop editor writes the same shape an author writes by hand.
  5. No new spec primitive — solve this with the rules already shipped (records, refs, cascade, variants).

The base format gives us all the parts already. This ADR codifies the canonical assembly.

Decision

Each block is its own record under a snippets collection (conventionally /snippets/<name>.json, but the name is up to the site). The page record holds an ordered array of refs in a reserved field named sections:

{
  "@type": "WebPage",
  "title": "Home",
  "sections": [
    "ref:/snippets/hero-home",
    "ref:/snippets/mission",
    "ref:/snippets/featured-stories"
  ]
}

At read time the ref resolution pipeline (02-references.md §11.4) inlines each referenced record. The adapter iterates the resolved array and renders each section by its @type (or any other shape-discriminating field), looking up a component in its own section-type map.

The three referenced snippet records are ordinary Mosaic records:

// /snippets/hero-home.json
{ "@type": "Hero", "title": "Welcome", "image": "/hero.jpg", "align": "center" }

// /snippets/mission.json
{ "@type": "MissionStatement", "body": "Build small, ship often." }

// /snippets/featured-stories.json
{ "@type": "Grid", "items": ["ref:/blog/hello", "ref:/blog/refs-explained"] }

Rendered HTML stack (adapter-defined; illustrative):

<section class="hero hero--center">
  <h1>Welcome</h1><img src="/hero.jpg">
</section>
<section class="mission"><p>Build small, ship often.</p></section>
<section class="grid">…two BlogPosting cards…</section>

The field name sections is a convention (not yet a reserved name in the spec). When this pattern proves out in production adapters, the mosaic-web profile MAY add a normative clause reserving the name; for now it works as a plain Mosaic field.

Consequences

Alternatives considered

Cross-references