Skip to content
HomePagesHomePages template kit

Slots

What a slot is — the one thing a section declares as content — and why a slot's kind and its source vocabulary are closed sets rather than open ones.

A section’s schema is a list of slots, and nothing else. A slot is content that reaches the page per deliverable, and that a user can open the editor and change. Everything a section renders that is not a declared slot is fixed at author time — it is markup the renderer owns, invisible to the editor and to fill.

The pipeline reads a section’s declarations without ever running the section’s own code — fill never calls your component, and neither does the editor’s sidebar; both act on what the schema says, not on what your markup happens to do. See how your code runs at exactly two moments, and fill is not one of them. For that to work, the editable surface has to be derived from the declaration, never inferred from the rendered page. Two consequences follow, and are worth stating as consequences rather than rules: content the schema never declares as a slot cannot be edited, however obviously editable it looks in the markup, and a slot the schema declares but the render never shows is a defect the kit’s own consistency check reports, not a silent no-op.

The deeper reason is that a slot’s kind has to come from a closed set. Two separate consumers each have to understand every kind that exists: the editor has to know how to present it for a person to change, and fill has to know how to produce a value for it from a property’s facts. A kind either consumer met that it did not recognize would simply stop working for that piece of content — so the kit ships the set of kinds rather than a way to invent one. The same closure applies one level down, to how a slot’s value is sourced: it names a known property fact or a value the section computes, both drawn from a vocabulary the kit owns, which is what turns a typo in a source binding into an error where you wrote it rather than a value that silently never fills.

An author composing a schema chooses along a handful of axes, and every one is a short declaration rather than code:

  • Scalar or collection. A slot holds one value, or an ordered list of them — see the slot kinds for the full set and what each one holds.
  • Where the value comes from. A slot names a known property fact, a computed value, or an AI fill decision written in prose — declared in the schema.
  • Whether it is grouped into an editor card. Several slots can be collapsed into one card in the editor sidebar — a presentation grouping only, with no effect on fill — also in the schema.
  • Whether a display variant switches rendering. A variant’s case is seeded before fill runs — from the property’s facts, or by an AI decision — and the user may switch it unless it is locked; a slot can gate on the active case — again the schema.

Not the props type you hand-write. A renderer’s props are inferred from the schema, not authored beside it — see Renderer.tsx and how props derive from the schema. A hand-written parallel props type is exactly the drift that inference exists to remove.

Not a per-placement knob. A schema declares content, not rendering choices. A rendering choice nothing outside the section reads is a constant in the section’s own code, where a reader can see it beside the markup it governs; a presentation choice a user might genuinely overturn is a display variant.

Not styling. A picked value names which case was chosen, not how that case looks. The imagery and prose for a given pick is markup the renderer owns, and nothing about presenting one belongs in the schema.

Not a place for data fetching. By the time a renderer runs, a slot’s value has already arrived on its props. Nothing about how that value was produced — where it came from, or what decided it — belongs in the section’s rendering code.