JavaScript expression binding
A JavaScript expression binding evaluates a single JavaScript expression during server-side composition and exposes its value as a named variable — the JavaScript peer of the Sessel expression binding (e:). The expression runs server-side in dombase-js; for the broader server-side JavaScript surface see JavaScript in schemas and the JavaScript DOM API.
Namespace declaration
Declare the JavaScript binding namespace on an ancestor element:
<html xmlns:j="https://pagelove.org/Binding/JavaScript">
The namespace URI must be exactly https://pagelove.org/Binding/JavaScript. The prefix (here j) can be any valid XML prefix.
Attribute form
Each j:name="<expr>" attribute evaluates <expr> as one JavaScript expression and exposes its value under name. Attributes evaluate in declaration order, and existing bindings are visible to later expressions as bare identifiers:
<ul j:total="[10, 20, 30].reduce((a, b) => a + b, 0)"
j:doubled="total * 2"
pagelove:template="text/liquid">
<li>Total: {{ total }}</li>
<li>Doubled: {{ doubled }}</li>
</ul>
Here total is computed first with a JavaScript reduce, then doubled reads it as a plain identifier. The expression may also use await, so it can resolve a Promise before its value is bound.
In action
Given the page above stored on the host:
{% example "setup-js-summary", "body" %}
Fetching it renders the computed values:
GET /js-expr-summary.html
HTTP/1.1 200
<!DOCTYPE html>
<html>
<body>
<ul>
<li>Total: 60</li>
<li>Doubled: 120</li>
</ul>
</body>
</html>
What the expression can see
A j: expression runs as the body of one JavaScript function. In scope are:
- Earlier bindings on the same element — every
j:ande:(and resolvedr:resource) binding declared before this one, as a bare identifier holding its value (asdoubledreadstotalabove). request— the current request context, e.g.request.path,request.query.q,request.auth.claims.email.Context— an object that also holds all of the above under their names, for values whose names cannot be used as bare identifiers (see below).
A name is available as a bare identifier only when it is a plain JavaScript identifier and not a reserved word. A binding named after a keyword or with a non-identifier name (j:class, j:new, j:"first name") is still computed, but a later expression must read it as Context["class"] rather than a bare class.
Caching. Reading a per-user field of
request—request.auth,request.headers, and other identity members — marks the response as user-varying, so it is servedCache-Control: privateand excluded from the shared cache. Reading only shared fields (request.path,request.query,request.method) keeps the page publicly cacheable. Namingrequestwithout reading an identity member does not taint it.
Only the attribute form
Like e: Sessel bindings, JavaScript bindings exist only in the attribute form j:name="…". There is no <j:…> element form, and no standalone JavaScript expression type to declare on a schema — the j: attribute is the whole surface.
Sessel or JavaScript?
e: and j: are peers: each computes a value during composition and exposes it to later bindings and templates. Reach for:
- Sessel (
e:) — the default. Its${…}selector literals query the document and site graph directly (${[itemprop="price"]}.sum()), and it is the same language used in constraints, methods, and resolvers. - JavaScript (
j:) — when you would rather compute in JavaScript: array/string methods, arithmetic you already know, orawaiting a Promise-returning built-in (for examplecrypto.subtle). The same JavaScript runs in the browser, so the expression can be reused client-side.
They interleave freely on one element; use whichever reads best for each value. See the three bindings compared.
Error cases
| Condition | Result |
|---|---|
| JavaScript expression fails to parse, throws, or rejects | Request fails with an HTML-Microdata error during composition |
Namespace URI is not exactly https://pagelove.org/Binding/JavaScript |
j: attributes are ignored — no bindings are created |
See also
- Sessel expression binding — the Sessel peer (
e:) - Resource Binding — CSS selector-based data binding (
r:) - JavaScript in schemas — the same server-side JavaScript runtime, in schema slots
- JavaScript DOM API — traversing and building markup from JavaScript
- Templating — using bound values in Liquid templates
- Method Elements — the general attribute-form dispatch mechanism
j:attributes use under the hood