Skip to content
HomePagesHomePages template kit

Preview edge cases

Preview a section's structural edge cases.

Preview a section’s structural edge cases.

Add entries under states in fixtures.ts — one FixtureSpec per state, built the same way base is. A states entry is for a DESIGNED case, not raw coverage: nullability and empty-slot coverage (every slot rendered empty) is derived automatically from the section’s schema, so a fixture state is for a case the section renders differently — a content-length branch, a variant branch, an override, or several combined.

// fixtures.ts — a content-length case and a variant-branch case
export const fixtures = defineFixtures(
schema,
(scenario) => ({
base: scenario("luxuryMultiUnit", {
summary: "A 12-unit mansard Victorian moments from the Emerald Necklace.",
}),
states: {
// Content-length branch: exercises a long value's wrap/expand behavior.
"long-summary": scenario("luxuryMultiUnit", {
summary:
"A 12-unit mansard Victorian moments from the Emerald Necklace, with a " +
"terrazzo lobby, an on-site gym, quartz kitchens throughout, and a " +
"top-floor penthouse with a private rooftop terrace and skyline views.",
}),
// Variant branch: exercises the layout under the display variant's other
// case. `.at()` takes a bare case string, checked at resolve time against
// the cases `display:` declares — see The schema system § Display.
compact: scenario("luxuryMultiUnit", {
summary: "A 12-unit mansard Victorian moments from the Emerald Necklace.",
}).at("multi"),
},
}),
);

Each state is complete, not a diff against base. A state resolves independently from its own scenario(...) call: every fact-bound and compute()-bound slot resolves fresh against that state’s scenario, and every authored slot you don’t repeat resolves to nothing rather than quietly falling back to base’s value. Repeat an authored slot in every state that needs it — "long-summary" above restates summary because nothing else would supply it. Each state is a selectable fixture in the dev preview, so every one you add is there to render and review alongside base.

A state can also be designed to look different against a sparser property — fewer units, no logo, no video — rather than a content-length or variant branch. Source that kind of state from a different scenario, not from hand-picked overrides — just name a different ScenarioKey in the state’s own scenario() call:

// fixtures.ts — a `sparse` state sourced from a different scenario
export const fixtures = defineFixtures(
schema,
(scenario) => ({
base: scenario("luxuryMultiUnit", {
summary: "A 12-unit mansard Victorian moments from the Emerald Necklace.",
}),
states: {
sparse: scenario("sparseSingleFamily", {
summary:
"A classic center-hall colonial with an updated kitchen and original " +
"hardwood floors throughout.",
}),
},
}),
);

Every fact-bound and compute()-bound slot in sparse resolves against sparseSingleFamily’s own facts — there is no way for luxuryMultiUnit’s values to leak through, even for a slot the state doesn’t mention. Fill the authored slots you do need to state the same way you filled base — by the slot’s fill-spec source, never with a placeholder. See the fill-by-source rule and Pick a scenario for the picker and helper cheat-sheet.

The states entries under Steps — nothing else moves. Renderer.tsx is untouched, and section.ts moves only in Add a variant — the guide that declares the display variant whose cases .at() selects from.

Verify with the author loop.

  • fixtures-invalid — a states entry is malformed, and the message names the path inside the module it failed at.
  • section-unrenderable — the scenario a state names cannot supply a fact one of the section’s slots needs, so fixtures.ts throws while it loads.
  • fixtures.ts — the fixtures.ts contract: defineFixtures/scenario (complete, non-merging states), the scenario breadth table, and the fill-by-source rule.
  • Pick a scenario — the scenario picker and helper cheat-sheet a scenario-swapped state builds on.
  • template-kit dev — the preview server that renders each fixture state across the widths your design swaps at.