no-slot-marker-literal
"No hand-written data-slot-* attributes or string literals — markers come from the Slot primitives."
Venue: eslint — No hand-written data-slot-* attributes or string literals — markers come from the Slot primitives.
No data-slot-* may be hand-written in section code. The rule reports, in any .ts or
.tsx file:
- a JSX attribute whose name starts with
data-slot-—<li data-slot-item={i}>; - a string literal containing
data-slot-— an attribute smuggled through a spread object ({ "data-slot-id": "headline" }) or read back withquerySelector('[data-slot-id]'); - a template literal containing
data-slot-in its fixed text.
Comments are prose and are never reported. Building a selector from the kit’s exported
attribute constants (`[${ATTR_SLOT_ITEM}]`) is not a literal and passes — the
constant tracks the contract, a spelled-out string does not.
Reason
Section titled “Reason”The data-slot-* attributes are the editor’s wire format, and every one of them is
emitted by a Slot.* primitive from your schema. That is a guarantee the
missing-slot-marker check can prove: what the primitives
emit is derived from the same schema the editor reads, so the two cannot disagree.
A hand-written marker is the one way around that guarantee. A mistyped slot key in a string is not a compile error — it is a marker that silently addresses nothing, or worse, the wrong slot: the editor patches an element the schema never meant. Writing markers by hand is how identity drifts; reading them by hand couples your code to how the kit chooses to emit them, which is not part of its contract.
Render the slot through its primitive — the primitive is the marker. Whatever
element the markup needs, the primitive can be it via as, and its remaining props are
that element’s own.
Before
Section titled “Before”import { bindSlots, Section } from "@homepages/template-kit";
import { schema } from "./schema.js";import type { Props } from "./schema.js";
export function Renderer({ slots }: Props) { const slot = bindSlots(schema, slots); return ( <Section> {/* template-kit/no-slot-marker-literal: a hand-written marker */} <h1 data-slot-id="headline">{slot.headline.value}</h1> </Section> );}import { bindSlots, defineSchema, Section, Slot, text } from "@homepages/template-kit";import type { SectionProps } from "@homepages/template-kit";
const schema = defineSchema({ label: "Hero", slots: { headline: text.medium({ label: "Headline" }), },});
type Props = SectionProps<typeof schema>;
export function Renderer({ slots }: Props) { const slot = bindSlots(schema, slots); return ( <Section> <Slot.Text slot={slot.headline} as="h1" /> </Section> );}See also
Section titled “See also”- The marker contract — what the markers mean and who reads them.
- Slot primitives — the primitive for every slot kind, and the marker each one emits.
missing-slot-marker— the rendered-tree half: the marker a primitive emits must actually reach the DOM.