8. Components and repeaters

Declare data once, then stamp markup from it with `wdoccomponent, slots, and wdocrepeater`.

After this lesson you can

- Declare a wdoc_component with defaulted wdoc_slots - Fill slots via interpolated strings and bare field references - Stamp one instance per data row with wdoc_repeater

Before you start: A book site and its table of contents

A component is a reusable fragment of ordinary wdoc markup with named slots: declare wdoc_slots and a wdoc_body, then instantiate the component by its own name anywhere a block is allowed. Slot values land in text through $"…${slot}…" interpolated strings; bare references (like class = [status]) need no prefix. A slot with a default is optional at the call site.

A wdoc_repeater renders its body once per element of each, binding the element to the symbol named by as — combined with a component it stamps one card per data row. The same repeater emits pages at the document root and chapters inside a toc, so navigation can be data-driven too.

§ 1Exercise: One card per metric

Declare a metric-card component and a data list, then render one card per row with a repeater.

wcl
let metrics = [
  { name: "CPU",    pct: 42, sev: "warning" },
  { name: "Memory", pct: 88, sev: "error" },
]

wdoc_component metric_card {
  wdoc_slot label
  wdoc_slot value
  wdoc_slot status { default = "note" }
  wdoc_body {
    callout $"${label}" { class = [status]  body = $"Currently at **${value}%**" }
  }
}

page health { sites = [:docs]
  h1 "Health"
  wdoc_repeater { each = metrics  as = :m
    metric_card { label = m.name  value = m.pct  status = m.sev }
  }
}

Expected result

The page shows one callout per data row — a warning-coloured CPU card and an error-coloured Memory card — with the values interpolated into the bodies.

Hint

Interpolated strings need the $ prefix; a plain "…" renders ${…} literally.