Skip to main content

When to use form expressions

Use a form expression to derive a default, control visibility or editability, compute a value, shape action text, or look up service data for the current form experience. It is not a server-side permission system and it is not a substitute for a workflow approval. The full callable catalog is in Form helpers and lookup filters. This guide explains how to use those helpers safely. KayanOS form field settings for the Citizen Service Intake form, including visibility, repeatable, and validation-expression controls.

Form roots

Use small, local expressions. A condition for one field should usually depend on that field’s siblings or a clear form value, not on a long path across several repeaters.
Legacy $.status and $.request_amount.value expressions remain supported. The expression editor suggests their $values equivalents.

Repeatable patterns

In a looped repeatable, $item is the source loop item and $index is its zero-based position. In a user-controlled repeatable, use the instance/sibling values that exist in the current form structure.
Do not use a repeatable count as a hidden policy gate. Validate the actual field values that make a request eligible.

UI checks are not authorization

hasVerb, hasVerbOnRecord, hasScope, and hasAnyScope can adapt what a member sees in a form. They do not grant access. In particular, verb helpers return true during server evaluation, so an expression using them cannot be your only enforcement point.
Use this to show a reviewer-oriented block. Keep actual authorization and state-transition rules in the relevant server-side service policy.

Record lookup: keep it narrow, private, and non-authoritative

getRecord and getRecords are form data conveniences. They can return an empty/null-like result when the form context is unavailable or a lookup times out. Their backing lookup runs through a system-level data path; it does not filter results using the current participant’s ordinary record or field permissions, role, or scope. It also has no lookup-limit argument, so a broad filter can load every matching record. That makes three boundaries explicit:
  1. hasVerb* and hasScope* can change presentation only; they do not authorize an action.
  2. getRecord and getRecords must never decide whether a participant is authorized or entitled to data.
  3. A lookup result must never be rendered to a public or otherwise unauthorized participant. A hidden field is not an access-control mechanism.
Use a selective filter against an entity and fields deliberately designed for this purpose, then safely handle no result:
Do not copy this as a broad public lookup pattern. Do not query an entity that carries personal, financial, or operational data merely to decide visibility. Prefer a small purpose-built record with only the minimum non-sensitive fields, an equality filter tied to the current request, and an owner-reviewed output. Before publishing a public form, test with a public participant and prove that no value returned by a lookup is rendered, exported, or used to authorize an action for that participant.

Build filters with f.

The f. functions build a database filter object for getRecords; they do not filter an arbitrary list in memory. The most useful pattern is a small conjunction:
Use f._in when a readable, unambiguous inclusion helper is preferred. Test the exact field keys and stored option values. Do not build a broad lookup and then hide results with a later expression.

Weekdays and service shifts

isWeekend(date, entityId?) and isWeekday(date, entityId?) can use configured shift work days when an applicable entity and service data are available. Without that data, they fall back to Saturday/Sunday. Treat them as online regular-form helpers and test the target organization’s schedule.

Offline form limits

Offline forms block getRecord, getRecords, hasVerbOnRecord, hasVerb, hasScope, and hasAnyScope. They also restrict several data-backed form features. Keep offline expressions self-contained: field values, simple conditions, and deterministic general helpers.
Validate an offline form before publishing. Do not rely on a function that happens to be suggested by the editor if the offline validator blocks it.

Test matrix