Developers

Primitives vs components

Choose the right abstraction: native HTML with data-macro-key, or a MacroNodeDefinition block with a JSON payload and render().

Rule of thumb
One heading, one image, one link → primitive. Hero, pricing table, slider, multi-field card → component.

Comparison

NameTypeDescription
StoragePrimitive: typed node value. Component: JSON payload (+ optional slot children).
MarkupPrimitive: native HTML. Component: host tag + render()-built DOM.
SchemaPrimitive: built-in. Component: fields[] synced to node_definitions.
EditingPrimitive: inline / specialized panels. Component: form + optional custom sidebar.

Primitives

hero.html
<h1 data-macro-key="hero.title">Build faster</h1>
<img data-macro-key="hero.image" src="/hero.jpg" alt="Hero" />
<a data-macro-key="hero.cta" href="/signup">Get started</a>
  • Macro owns DOM bindings and overlay UIs for built-ins.
  • Tag inference picks macro/text, macro/image, macro/link, …
  • Best for marketing copy, simple media, and form field values.

Deep dive: Primitive reference.

Components

home.html
<acme-hero
  data-macro-key="home.hero"
  data-macro-type="@acme/hero"
></acme-hero>
  • You own HTML structure and render().
  • One JSON payload per key + locale; fields[] drive the sidebar.
  • Optional slots for repeaters or projected Light DOM.

Guide: Custom components.

Decision guide

Do

  • Start with primitives; extract a component when fields and layout grow together.
  • Prefer Store components when a validated bundle already solves the block.
  • Use items slots for editor-managed lists inside a component shell.

Don’t

  • Don’t wrap a lone H1 in a custom component “for consistency”.
  • Don’t put unrelated page copy into one giant component payload.
  • Don’t fork Store bundles in place — use slots or design fields.

Content vs styled (components)

Structure and behavior only — inherit the host site. At most a few tokens (--macro-accent, --macro-radius). Reference: content-slider.