Skip to content
HomePagesHomePages template kit

The marker contract

Why a section's rendered DOM carries attributes naming the declarations behind it, and what that contract does and does not ask of your markup.

A section’s rendered DOM carries attributes that name which declaration produced each piece of it — enough for something outside your renderer to point at an element and know which schema key put it there. The whole contract fits in one sentence: to render slot X, you use slot X’s primitive — there is nothing else, and the marker cannot be anywhere else. The attribute names themselves are in the reference; this page is about why they exist and what they do, and do not, obligate you to do.

The pipeline establishes that your code runs at exactly two moments, and that in both of them the platform hosting your renderer never sees your component — only the DOM it produced.

That is the constraint the editor lives inside. When someone clicks a piece of content on the canvas, the editor has to resolve that click back to the schema key that produced it — but it has never had your component to inspect, only the markup your renderer emitted, and that markup is the only thing the two sides of that boundary share. So the identity of a piece of content has to travel in the DOM itself, as an attribute on the element carrying it, because there is nowhere else for it to live.

The design choice that follows is where the markers sit: on your own elements, not on a wrapper the kit inserts around them. A slot’s binding carries its identity, and its primitive derives the marker from it and places it on the element the primitive renders — the element you named via as, with that element’s own props. Because the marker rides on an element you already wrote rather than one the kit owns, the kit never needs a layout layer of its own, and your DOM stays exactly the DOM you wrote.

The primitive is the marker, and that identity is deliberately exclusive: there is no marker-only carrier, no bag of attributes to spread onto an element of your own, and no second route identity could arrive by. When a primitive seems not to fit the markup you need, the answer is that the primitive can be that markup — as accepts any element, the remaining props are that element’s own, and your children render inside — never that you attach the marker some other way. One primitive per slot means the editor’s picture of the page and your markup cannot disagree.

The same design is why a slot can be marked in several places at once: each rendered copy of a slot’s value carries its own marker, is patched live, and is its own editing target — a headline printed twice is editable in both spots, not only the first. A copy that should never resolve a click — a carousel clone, a decorative mirror — declines selection with a render-time lever (selectable={false}); it keeps its identity and keeps receiving patches, because a copy without identity would visibly lag its siblings.

The direction of travel matters. Every marker but one is emitted for you — the primitives that render a slot read its own schema and put the right attribute on the right element, so you never author a marker’s name yourself. One attribute goes the other way: it names the deliverable’s own instance, and it is written by the platform onto the section root, not by anything in your renderer. The full set, and which is which, is on the reference page.

Nothing about the slot primitives dictates your DOM beyond the one element each one renders. There is no wrapper you didn’t ask for, no forced tag, no required container, and no ordering constraint beyond what sidebar-order asks of the markers themselves. Layout, headings, links, icons, cards, tables — all plain JSX around them.

A marker names the element carrying a slot’s value, and which element that is depends on what the slot declares — an image slot’s marker can land on a framed wrapper, on the image itself, or on a generated picture element, depending entirely on the schema. A CSS selector written against a marker attribute is written against that choice, and a schema change moves it out from under the selector without touching a line of your renderer. Style your own classes, and leave the markers to the editor.

Markers are not attributes to write by hand

Section titled “Markers are not attributes to write by hand”

Every marker other than the platform’s own is emitted for you; writing one in your JSX by hand does not create a slot, because a slot exists only where the schema declares it. Both halves of that are checked: no-slot-marker-literal rejects any hand-written data-slot-* in section code, and missing-slot-marker reports a declared slot that never reached the DOM.

  • Slot primitives — the full set of marker attributes, and the primitive that emits each one; whatever element your markup needs, the primitive can be it via as.
  • missing-slot-marker — the check that proves each editable slot reached the rendered page.
  • sidebar-order — the one ordering constraint the markers themselves carry.
  • Server and client — why the renderer that emits these markers ships no JavaScript, and where browser-side code goes instead.