Skip to main content
Templates are data: they select and arrange values, and the author supplies every literal. The forms below are the complete vocabulary.

Node forms

  • STRING — a text node: “Hello”
  • BIND — { “bind”: “path.to.value” } renders the value as text; ’.’ binds the scope itself
  • PATHS — dot paths against the current scope (each item inside EACH). Escapes: ‘meta.xreadspayload.meta;meta.x' reads payload.meta; 'root.x’ reads the top-level data from any depth; ‘parent.xstepsoutofoneenclosingEACHpertoken(parent.x' steps out of one enclosing EACH per token ('parent.parent.x);parent.x'); 'index’ is the zero-based position in the innermost EACH
  • EACH — { “each”: “path.to.array”, “template”: <node>, “empty”?: <node> } repeats template with each item as scope
  • WHEN — { “when”: “path”, “template”: <node>, “else”?: <node> } renders template when the value is truthy
  • ELEMENT — { “tag”: “div”, “attrs”?: { “class”: “x”, “src”: { “bind”: “path” } }, “children”?: [<node>…] }
  • ATTR MAP — { “bind”: “status”, “map”: { “do-not-contact”: “wg-status wg-status-danger”, “active”: “wg-status wg-status-success” }, “default”: “wg-status” } — the bound value SELECTS one of your literals (semantic classes from data values); a miss emits default, or empty without one
  • ATTR PREFIX — { “bind”: “email”, “prefix”: “mailto:” } — emits prefix+value only when the value is non-empty (mailto:/tel: links; both schemes are allowed on href). One transform per attr value: map OR prefix, never both
  • ACTION — an element may carry “action”: { “ref”: “<shared action name>” } or an inline { “definition”: { “kind”: “prompt”, “text”: [“Show the forecast for ”, { “bind”: “city” }] } } / { “definition”: { “kind”: “http”, “method”: “GET”, “url”: “https://…”, “input”: <schema>, “output”: <schema> } }, plus “input”: { “<field>”: “<path>” | { “const”: <value> } } and “output”: { “mode”?: “replace”|“merge”|“patch”, “path”?, “map”? }. Bindings resolve at render time; buttons and links (never both href and action) become activatable in Apps hosts. A widget-level “load” (http GET only) runs once when the widget first renders

Safety rules

  • Attribute names matching on* and srcdoc are forbidden (FORBIDDEN_ATTRIBUTE).
  • script, iframe, frame, frameset, object, embed, style, link, meta, base, template and noscript are forbidden (FORBIDDEN_TAG) — a template is data, never active content.
  • On href, src, action, formaction, xlink:href, data, poster, ping: only http, https, mailto, tel schemes or relative references survive rendering.
  • Exception: an img element’s src additionally accepts base64 data:image/*;base64, URIs.
  • Bindings only ever produce text and attribute strings — bound values can never inject markup.

Bounds

Validation rejects deeper nesting; interpretation stops at the node budget and marks the render truncated. Actions bound from templates are specified on Action definition; entry shapes on Authoring contract.