Skip to content
HomePagesHomePages template kit

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 with querySelector('[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.

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.

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>
);
}