Expressions
XML page expressions use a safe JavaScript expression subset parsed with Acorn. LongLink evaluates only approved syntax against the XML runtime scope; it does not execute arbitrary JavaScript.
Syntax Forms
$draft.titlereads a runtime value and creates a writable binding for controls that support bindings.${draft.title}evaluates a typed expression and returns the expression result./requests/${params.request}interpolates expression results inside a string parameter.- Plain text stays literal unless it is a dotted runtime path, a
$reference, or contains${...}interpolation.
xml<TextInput label="Task title" value="$draft.title" /><Text count="${tasks.length}" i18n="tasks.count" /><Link to="/requests/${params.request}" i18n="requests.open" />
Runtime Scope
Expressions can read values exposed by setup nodes, route params, and loop scopes.
Statevalues are reactive local page objects, such asdraft.title.Queryvalues are JSON responses stored under their query id, such astasks.length.Forexposes the item alias andindexinside the loop body.- Dynamic page files expose route parameters through
params.
xml<Query id="tasks" path="/api/tasks" /><For each="$tasks" as="task"><Text i18n="tasks.row" values="${{ index: index + 1, title: task.title }}" /></For>
Operators
Supported operators cover page conditions, derived values, and request payloads.
- Arithmetic:
+,-,*,/,%, and**. - Equality and comparison:
===,!==,==,!=,<,<=,>, and>=. - Logical expressions:
&&,||,??, and!. - Membership:
status in ['open', 'pending']checks strings, arrays, and object keys. - Conditional values:
condition ? yes : no. - Optional chaining:
user?.profile?.name.
xml<Button isDisabled="${!draft.title || saving}" i18n="tasks.create" /><Text if="${task.status === 'open'}" i18n="tasks.title" values="${{ title: task.title }}" /><Badge label="${task.priority >= 5 ? 'High' : 'Normal'}" /><Text i18n="tasks.owner" values="${{ name: task.owner?.name ?? 'Unassigned' }}" />
Arrays, Objects, and Templates
Wrapped expressions preserve typed values, so arrays and objects can be sent directly to actions.
xml<Actionaction="/api/tasks"invalidate="${['tasks']}"json="${{ title: draft.title, priority: Number(draft.priority) }}"><Button i18n="tasks.create" /></Action><Text i18n="tasks.summary" values="${{ summary: `Task ${task.id}: ${task.title}` }}" />
Safe Calls
Only whitelisted global helpers can be called from expressions.
- Type helpers:
String(value),Number(value), andBoolean(value). - Array helper:
Array.isArray(value). - Math helpers:
Math.abs,Math.ceil,Math.floor,Math.max,Math.min,Math.round, andMath.trunc.
xml<Text i18n="tasks.id" values="${{ id: String(task.id) }}" /><Text if="${Array.isArray(tasks) && tasks.length > 0}" i18n="tasks.ready" /><Text i18n="tasks.total" values="${{ total: Math.round(total) }}" />
Bindings
Writable form bindings use the $ reference form. A typed expression can read a state field, but it does not create a writable control binding.
xml<State id="draft" title="" /><!-- writable --><TextInput label="Task title" value="$draft.title" /><!-- read-only expression result --><Text i18n="tasks.draftTitle" values="${{ title: draft.title || 'Untitled' }}" />
XML Escaping
XML attributes must still be valid XML. Escape reserved characters before the expression reaches the LongLink evaluator.
- Use
<for less-than comparisons. - Use
&&for logical and. - Quote XML attributes with single quotes when the expression contains many double quotes.
xml<Text if="${amount < 100}" i18n="orders.small" /><Text if="${ready && tasks.length > 0}" i18n="tasks.ready" />
Unsupported Syntax
Expressions are intentionally read-only and sandboxed.
- Arbitrary function calls and object method calls are blocked.
- Assignments, updates, constructors, classes, imports, and dynamic code execution are blocked.
- Inherited properties and unsafe prototype names are not readable.
xml<!-- blocked --><Text i18n="tasks.title" values="${{ title: task.title.toUpperCase() }}" /><Text i18n="tasks.created" values="${{ created: new Date() }}" /><Text i18n="tasks.unsafe" values="${{ unsafe: task.__proto__ }}" />