Expressions & calculations

Insert live data into any block with {{$…}} expressions, compute with JSONata, and reshape bindings with transforms.

#Expressions: {{$…}}

Any text-bearing block config (headings, text, badges, stats, tiles, buttons, card link patterns, calendar month…) can embed live values:

Expression Resolves to
{{$binding.key.field}} A field from a binding. On a list binding this reads the first row — handy for "top item" callouts.
{{$binding.key}} The whole binding value — useful for computed bindings (see transforms).
{{$record.field}} The current record — on record pages, and row-scoped inside repeaters.
{{$user.name}} / {{$user.email}} / {{$user.role}} The viewing user.
{{$site.name}} The instance name.
{{$url.param}} A URL query parameter.
{{$time}} The render time (ISO).

Missing values render as empty — a typo never breaks the page. Plain-text output is always escaped; HTML modes sanitise after insertion, so data can't inject markup.

#Calculations: {{= … }}

For math, string operations, and aggregates, use a JSONata calculation:

{{= $count(binding.movies.data) }} films
{{= "$" & $formatNumber($sum(binding.movies.data.revenue) / 1e9, "#,##0.0") & "B" }}
{{= $substring(record.release_date, 0, 4) }}

Calculations see binding, record, user, site, url, and now. They evaluate against the page's top-level data — use {{$record.field}} for per-row values inside repeaters.

#Binding transforms

A binding's Transform field runs JSONata over the fetched value before blocks see it. Three patterns cover most needs:

data[status="published"]                 → filter rows
data[vote_average >= 8]^(>vote_average)  → filter + sort (descending)
data ~> |$|{"decade": $string($floor($number($substring(release_date,0,4))/10)*10) & "s"}|
                                         → derive a field on every row
{"revenue": $sum(data.revenue), "count": $count(data)}
                                         → compute an object; read it as
                                           {{$binding.key.revenue}}

Derived fields behave exactly like stored ones — chip rules, kanban lanes, and table columns can all use them. A failing transform keeps the untransformed data, so a bad expression can't blank a page.

Tip: a second binding on the same collection with a different transform costs nothing extra — collection queries are batched per render.