Writing templates
A template body is JSX-flavored markup. This page covers the body itself; directives (on:, bind:, class:list) have their own page.
Static text vs reactive state
Section titled “Static text vs reactive state”Plain {expr} renders once and is auto-escaped. read(machine, selector) creates a live binding:
<h3>{product.name}</h3> <!-- static --><p>Total: {read(cart, c => c.total)}</p> <!-- updates when the cart changes -->read() is only valid in text or as a whole attribute value. Mixing literal text with a read() in one attribute is a compile error — wrap the whole value in the selector instead.
Attribute bindings understand boolean semantics: a selector returning false/null/undefined renders the attribute absent (and a change patches it away with removeAttribute); true renders it present-and-empty. That’s how presence-toggled attributes work end to end:
<button disabled={read(cart, (c) => c.count === 0)}>Begin checkout</button>One platform caveat: checked, value, and selected as attributes set defaults only — a form control the user has touched ignores them. Live form state is bind: territory.
Conditionals: when and match
Section titled “Conditionals: when and match”Both are callbacks, not components, so a branch’s body isn’t evaluated unless it’s chosen.
{when(read(cart, c => c.isEmpty), () => <p>Your cart is empty.</p>)}
{match(read(order, o => o.status), { pending: () => <span>Pending</span>, shipped: () => <span>Shipped</span>,})}Use when for one condition, match to pick one of several by value.
Loops: each
Section titled “Loops: each”<ul> {each(read(cart, c => c.items), (item, i) => <li>{item.quantity} × ${item.unitPrice.toFixed(2)}</li> )}</ul>Trusted HTML with raw()
Section titled “Trusted HTML with raw()”raw() emits a string verbatim, bypassing escaping. Pass only markup you constructed or trust:
import { raw } from '@statorjs/stator/template'<div>{raw(sanitizedHtml)}</div>Structured data with <JsonLd>
Section titled “Structured data with <JsonLd>”For a schema.org block, use the typed component rather than a hand-written <script>:
import { JsonLd } from '@statorjs/stator/components'<JsonLd json={{ "@type": "Product", name: "Pocket Notebook" }} />Composing components
Section titled “Composing components”A capitalized tag invokes a component; lowercase is HTML. Pass machines and data as props:
<ProductList products={products} cart={cart} />Layouts and named slots (<children>) are covered in Routing.