Skip to content
HomePagesHomePages template kit

sidebar-order

"Schema slot order must match the order the page renders them in."

Venue: check — Schema slot order must match the order the page renders them in.

The editor renders one sidebar card per group (and one per ungrouped slot), in the order the schema declares them. This check server-renders the section’s baseline fixture, reads the first-appearance order of the slot markers in the resulting HTML, and asserts that it matches the schema’s declaration order.

Three carve-outs, each of which looks like a bug if you don’t know about it:

  • A slot rendered more than once counts at its first marker. An address shown in a header and again in a footer is ordered by the header.
  • Order within a group is not checked, and neither is contiguity. A group’s members may appear in any order on the page, and other slots may sit between them. Responsive layouts legitimately do both, and the sidebar collapses the group into one card anyway.
  • A slot declared but never rendered is excluded. It has no position on the page, so it cannot contradict one.

Two files describe the same section in two different orders, and only one of them is visible to the person editing. The failure mode is drift: you reorder the markup — move the eyebrow above the headline, promote the price — the schema keeps its original order, and the sidebar quietly stops matching the page.

Nothing breaks. The section renders, the slots fill, and every card still works. The user just finds that the second card edits the first thing they see, and stops trusting the panel. This check makes that drift impossible to ship rather than merely unlikely.

Reorder the schema, not the page. The page’s visual order is the truth — it is what the user is looking at — so bring the schema to it: reorder the slots keys so declaration order matches the page’s top-to-bottom order. That is the whole fix even when you have group cards — a card sits where its first member is declared, and the order you wrote the layout array in decides nothing.

The schema declares headline first, the page renders eyebrow first:

// sections/hero/section.ts — template-kit/sidebar-order
import { defineSchema, type SectionProps, text } from "@homepages/template-kit";
export const schema = defineSchema({
label: "Hero",
slots: {
headline: text.medium({ label: "Headline" }),
eyebrow: text.short({ label: "Eyebrow" }),
price: text.short({ label: "Price" }),
},
});
export type Props = SectionProps<typeof schema>;
// sections/hero/Renderer.tsx — the page, top to bottom: eyebrow, headline, price
import { bindSlots, Section, Slot } from "@homepages/template-kit";
import { schema } from "./section.js";
import type { Props } from "./section.js";
export function Renderer({ slots }: Props) {
const slot = bindSlots(schema, slots);
return (
<Section>
<Slot.Text slot={slot.eyebrow} as="p" />
<Slot.Text slot={slot.headline} as="h1" />
<Slot.Text slot={slot.price} as="p" />
</Section>
);
}

The Renderer is untouched. The schema moves:

sections/hero/section.ts
import { defineSchema, type SectionProps, text } from "@homepages/template-kit";
export const schema = defineSchema({
label: "Hero",
slots: {
eyebrow: text.short({ label: "Eyebrow" }),
headline: text.medium({ label: "Headline" }),
price: text.short({ label: "Price" }),
},
});
export type Props = SectionProps<typeof schema>;