bind, element, each and when — compile into an ordinary renderer, and every value that reaches the output is either one of your literals or payload data rendered as escaped text. There are no expressions: data selects, and you supply every literal. This page is the human version of the rules; the generated Template DSL reference and Limits carry the exact lists and numbers.
Node forms
- Text and bind
- Element
- Each
- When
A string is a text node.
{ "bind": "path" } renders the value at that path as text; "." binds the current scope itself.Attribute transforms
A bound attribute value may carry one transform,map or prefix, never both.
map lets a data value select one of your literals. A hit emits that key’s literal; a miss emits default, or an empty value without one. Data never contributes output characters.
prefix emits your literal followed by the bound value, but only when that value is a non-empty string, so an absent email yields no dead mailto: link.
Paths
Paths are dot notation againstpayload.data: items.0.name walks objects and array indices. Inside each, the scope is the current element. Four escapes exist:
Missing or non-traversable paths are blanks, not errors: empty text for
bind, no repetitions for each, the else branch for when. Interpretation never throws, whatever shape the data has.
What a template cannot do
- Run code. There are no expressions, functions or scripts. Bindings only ever produce text and attribute strings; a bound value of
<img onerror=x src=y>renders as those literal characters, not as an element. - Attach handlers. Attribute names matching
on*fail validation withFORBIDDEN_ATTRIBUTE, as dosrcdocand the renderer-reserveddata-wg-*names. They are skipped at render time as well. - Embed active content.
script,iframe,frame,frameset,object,embed,style,link,meta,base,templateandnoscriptfail withFORBIDDEN_TAG. - Smuggle URL schemes. On URL-bearing attributes (
href,src,action,formaction,xlink:href,data,poster,ping) onlyhttp,https,mailto,teland relative references survive; anything else,javascript:included, is dropped at render time. Aprefixvalue runs the same guard, so"prefix": "javascript:"is dropped like a boundjavascript:value. - Use
data:URIs, with one exception: animgelement’ssrcaccepts base64data:image/*;base64,URIs. - Nest without limit or render without bound. Validation rejects nesting past a fixed depth (
TEMPLATE_TOO_DEEP); interpretation stops at a node budget and marks the render truncated, becauseeachmultiplies template nodes by agent-supplied data length. The numbers are in Limits.
Validation errors
validateTemplate returns a structured error with a code (INVALID_TEMPLATE_NODE, INVALID_PATH, FORBIDDEN_ATTRIBUTE, FORBIDDEN_TAG, TEMPLATE_TOO_DEEP, INVALID_ACTION or CONFLICTING_ATTRIBUTES), a message, and a dotted path locating the node, such as children.0. The designer shows it at the offending node; the store refuses the entry on write.
Roots and wrapping
When the root interprets to anything but exactly one node (aneach at the root, for instance), the output is wrapped in a div with class wg-template. A single element root is emitted as is.
Elements may also carry an action binding: a button or a bound to a prompt or http action, never together with href. That form is covered in Actions and secrets.