Expressions
How values are resolved anywhere one is expected, from literals and references to scoped arguments.
Resolution and Scoping
Two rules govern how values are read:
Expressions work anywhere a value is expected: a prop value, a conditional's subject or branch, a map's source or template, an action's argument. They also stand in for literals at any depth inside a prop's objects and arrays; these are called deep expressions:
{
"type": "button",
"props": {
"label": "Submit",
"layout": { "direction": "horizontal", "gap": { "$data": "/gap" } }
}
}Resolution is a single pass over the document: a value an expression
returns is data, never re-interpreted as an expression. A data value
shaped like { "$data": ... } resolves to that object itself, not to a
further reference.
Resolution is also a function of the current data context: when the data context changes, resolved values MUST reflect the change (action arguments, resolved at dispatch time, are the stated exception). When and how the engine re-renders is the engine's concern.
Scoped arguments are read through $arg, within the construct that
injects them. A map injects $item and $index into its
template, an action injects the callback's positional
arguments $0, $1, …, and a translation tag injects $content. Outside
its construct, a scoped argument is invalid. See
Scoped Arguments.
Expression Types
An expression resolves to a single value: a literal, a data reference, a translation reference, an inline message, or a scoped argument. A field binding also appears in value position but additionally registers form state.
Literal Values
Static values matching the prop's expected type:
{
"type": "button",
"props": { "label": "Click me", "disabled": false }
}Data References
Data references resolve to a value from the data context using a JSON Pointer:
{ "$data": "/path/to/field" }Required
$data(string, JSON Pointer RFC 6901): Path to a field in the data. The empty pointer""resolves to the whole data context.
Returns: The value at that pointer location, or undefined when the path names no value. A prop resolving to undefined is treated as omitted; engines SHOULD report unresolved references during development.
When used in a prop, the prop MUST accept the type that this expression resolves to.
Example
{
"type": "text",
"props": { "children": { "$data": "/name" } }
}Translation References
Translation references resolve to a message from the active locale's catalog:
{ "$t": "form.greeting" }Required
$t(string): Catalog key of the ICU MessageFormat message to format (the classic MessageFormat syntax, not MessageFormat 2). The key is always a static string, so every key a document uses can be extracted without resolving it.
Optional
$params(object): Values interpolated into the message. Each value is itself resolved as an expression first, so data references, scoped arguments, and nested translation references are allowed.$tags(object): Elements rendering the message's tags, keyed by tag name. Each tag receives its formatted chunks as the$contentscoped argument, injected into the mapped element's scope.
Returns: Without $tags, the formatted message string; a key missing
from the catalog (or a pattern that cannot be formatted) formats to the
key itself, and engines SHOULD report missing keys during development.
With $tags, an ordered sequence of text chunks and rendered tag
elements.
Without $tags this expression always returns a string, so the prop MUST
accept string values. With $tags it returns renderable content and is only
valid in positions accepting nested elements. A tag the message uses but
$tags does not map renders its chunks bare. A translation reference is only
valid in value position: a top-level $t key on an element is a keyword, not
a prop.
Example
{
"type": "button",
"props": {
"label": {
"$t": "form.greeting",
"$params": { "name": { "$data": "/name" } },
"$tags": {
"strong": {
"type": "text",
"props": { "children": { "$arg": "$content" } }
}
}
}
}
}Inline Messages
Inline messages format an ICU MessageFormat pattern carried by the document itself, without a catalog lookup:
{
"$message": "{count, plural, one {# item} other {# items}}",
"$params": { "count": { "$data": "/count" } }
}Required
$message(string): The ICU MessageFormat pattern to format. Plurals, selects, and number and date arguments format in the active locale.
Optional
$params(object): Values interpolated into the pattern's arguments. Each value is itself resolved as an expression first, so data references, scoped arguments, and nested translation references are allowed.
Returns: The formatted string. A pattern that cannot be formatted (a syntax error, or a param the pattern cannot format) resolves to the pattern text itself; engines SHOULD report it during development.
This expression always returns a string. When used in a prop, the prop MUST
accept string values. An inline message is not translated: text shown to users
belongs in the catalog behind $t; $message
composes strings from data that no catalog owns, such as URLs and other
technical values.
Example
Building a link target from a data value:
{
"type": "anchor",
"props": {
"children": { "$t": "product.view" },
"href": {
"$message": "/products/{id}",
"$params": { "id": { "$data": "/productId" } }
}
}
}