Templates and Expressions
This page describes how Regor turns templates into live bindings, and what expression syntax is supported in runtime.
Template Sources
Section titled “Template Sources”Regor accepts templates from multiple sources in createApp(...) / defineComponent(...):
- HTML string (
template) - Existing DOM element (
element) - DOM selector (
selector) - JSON template (
json)
String templates are preprocessed before DOM parsing (table compatibility rules below).
Interpolation
Section titled “Interpolation”Regor supports two interpolation delimiters:
{{ expr }}[[ expr ]]
<p>{{ user.name }}</p><p>[[ user.name ]]</p>Interpolation Transform Rules
Section titled “Interpolation Transform Rules”When interpolation is enabled (RegorConfig.useInterpolation = true):
- Interpolation in text nodes is converted to directive bindings before normal bind phase.
- If an element contains exactly one interpolation token with only surrounding whitespace, Regor rewrites that element to use
r-text. - Mixed text + interpolation is split into text nodes and generated
<span r-text="...">nodes. - Subtrees marked with
r-preare skipped.
If useInterpolation = false, {{ ... }} and [[ ... ]] stay as plain text.
Table-Safe Preprocess for String Templates
Section titled “Table-Safe Preprocess for String Templates”For string templates, Regor preprocesses markup to keep table structures valid:
- Outside table scope:
<tr>/<td>/<th>may be rewritten to alias hosts (trx/tdx/thx) withis="r-*"markers.
- In table-sensitive positions:
- non-native direct children may be rewritten to safe hosts with
is="regor:OriginalTag".
- non-native direct children may be rewritten to safe hosts with
- Self-closing custom tags under row context are normalized to explicit open/close tags.
This avoids browser table parser dropping/reparenting custom nodes.
Where Expressions Are Used
Section titled “Where Expressions Are Used”Typical expression points:
- Text/content:
r-text, interpolation - Attributes/properties:
:x,.x,r-bind:x - Events:
@click,r-on:* - Control flow:
r-if,r-else-if,r-for - Styling:
:class,:style - Components:
:is,:context,r-context
Expression Scope and Resolution
Section titled “Expression Scope and Resolution”Expressions are evaluated against active context stack:
- Current app/component context
- Loop aliases (
r-for) - Slot switch contexts (when
head.enableSwitch = true) - Global context from
RegorConfig
Special identifiers:
$root: root-most context$parent: immediate parent context$ctx: full context stack arraythis: current context object$event: available in event/lazy evaluation paths
Regor auto-unrefs refs in expressions, so template code uses user.name, not user.name() / .value.
Supported Expression Syntax (Runtime)
Section titled “Supported Expression Syntax (Runtime)”Backed by Regor’s jsep/regorEval pipeline, templates support:
- Member access, optional chaining:
a.b,a?.b,a[k] - Calls/new:
fn(x),new Date(0) - Arithmetic/comparison/logical/bitwise operators
- Nullish coalescing / ternary:
a ?? b,ok ? a : b - Assignments and updates:
x = 1,x += 2,x++,--x - Arrays/objects/spread/computed object keys
- Arrow functions
- Template literals and tagged templates
- Regex literals
- Comma/compound forms
r-for Key Notes
Section titled “r-for Key Notes”Both forms are supported for expression-based keys:
key="row.id":key="row.id"
Nested paths such as a.b.c.d are supported.
Use stable domain IDs for predictable updates.
Practical Patterns
Section titled “Practical Patterns”- Prefer
r-textfor hot repeated rows. - Keep template expressions lightweight; move heavy logic into methods/computed refs.
- Use stable keys in lists.
- Use
r-preto protect literal template snippets from interpolation transform.
Advanced Samples
Section titled “Advanced Samples”1) Static-first page + dynamic island
Section titled “1) Static-first page + dynamic island”Use existing server-rendered markup and bind only the dynamic area.
<header> <h1>My Shop</h1> <div id="auth-island"> <button @click="toggle">{{ loggedIn ? 'Logout' : 'Login' }}</button> <span r-show="loggedIn">Welcome, {{ userName }}</span> </div></header>createApp( { loggedIn: ref(false), userName: ref('Ada'), toggle() { this.loggedIn(!this.loggedIn()) }, }, { selector: '#auth-island' },)2) Large list with stable keys and cheap row expressions
Section titled “2) Large list with stable keys and cheap row expressions”<ul> <li r-for="row, #i in rows" :key="row.id"> <strong r-text="row.title"></strong> <span>#{{ i }}</span> <small r-text="row.status"></small> </li></ul>Pattern:
:key="row.id"for stable identity.- Keep row expressions simple (
r-text+ direct paths). - Avoid heavy object construction inside row template expressions.
3) Dynamic component template switching (:is)
Section titled “3) Dynamic component template switching (:is)”<section :is="currentView" :context="{ item: selectedItem }"></section>createApp({ currentView: ref('UserView'), selectedItem: ref({ id: 1, name: 'Ada' }), components: { UserView, AuditView },})Use this when one region must swap templates/components based on state, while keeping parent bindings simple.
4) Slot template evaluated in parent context
Section titled “4) Slot template evaluated in parent context”const Shell = defineComponent('<section><slot></slot></section>', { context: (head) => { head.enableSwitch = true return {} },})<Shell> <p>{{ parentMessage }}</p></Shell>With head.enableSwitch = true, slot expressions can resolve against parent context naturally.
5) Interpolation-off region for literal template text
Section titled “5) Interpolation-off region for literal template text”const cfg = new RegorConfig()cfg.useInterpolation = falsecreateApp( { msg: ref('x') }, { element: root, template: '<pre>{{ msg }}</pre>' }, cfg,)or local skip:
<pre r-pre> {{ this stays literal }}</pre>Use these when docs/snippets must display {{ ... }} without binding.