props, you write JavaScript expressions in bindings that are evaluated against a data context. When the underlying data changes, bindings are re-evaluated and the UI updates automatically.
This guide covers the full binding system: how bindings work, the shape of the data context, loop scoping with for, computed bindings that reference named scripts, and the reactivity model that drives updates.
For the scripting language details and sandbox limitations, see the Scripting guide.
How Bindings Work
EveryUINode can have a bindings object that maps prop names to JavaScript expressions. At render time, each expression is evaluated with the current data context injected as ctx. The result replaces (or supplements) the corresponding value in props.
visible is a static prop (always true), while label is a dynamic binding that evaluates against the data context. If both props and bindings define the same key, the binding takes precedence.
Expression Evaluation
Binding expressions are evaluated by wrapping them in an immediately-invoked function:- Optional chaining:
ctx.dataObjects?.[0]?.path - Nullish coalescing:
ctx.value ?? 'default' - Ternary operators:
ctx.count > 0 ? 'Has items' : 'Empty' - Template literals:
`Total: ${ctx.count} items` - Array methods:
ctx.dataObjects?.filter(o => o.path === 'invoice').length - Arithmetic:
ctx.amount * 1.1
Binding expressions should be pure — they should not modify any state, make API calls, or produce side effects. The runtime may re-evaluate them at any time when the data context changes.
Data Context Shape
Thectx object passed to binding expressions contains the current data context. At the root level, it has the following shape:
Root Context
At the top level (outside anyfor loop), ctx contains:
| Property | Type | Description |
|---|---|---|
ctx.dataObjects | DataObject[] | All data objects from the workspace store |
ctx.tagMetadataMap | Map<string, any> | Tag metadata from the project store, keyed by taxonomy path |
DataObject Shape
Each data object inctx.dataObjects has the following properties (among others):
DataAttribute Shape
Accessing Data in Expressions
computed instead of a long inline expression.
Loop Scoping
Thefor configuration on a UINode renders the node once for each item in a source collection. Inside the loop, the data context is extended with loop-specific variables.
Loop Variables
| Variable | Type | Description |
|---|---|---|
$item | any | The current element from the source array. The name is configurable via itemAs. |
$index | number | The zero-based index of the current element. The name is configurable via indexAs. |
$parent | DataContextV2 | The parent data context (the context from before the loop started). |
$root | DataContextV2 | The root-level data context (always the top-level context). |
Nested Loops
When you nestfor iterators, each level creates a new scope. Use $parent to access the outer loop’s context:
When a nested loop uses the same
itemAs name as an outer loop, the inner variable shadows the outer one. Use $parent.$item to access the outer item. For clarity, consider using distinct names like $invoice and $lineItem.Key Expressions
Thekey field in ForConfig is evaluated per item and must produce a unique, stable value. This helps the renderer efficiently update the DOM when items are added, removed, or reordered.
Good key expressions:
"$item.uuid"— unique and stable"$item.id"— unique within a document
$index as a key, since it changes when items are reordered.
Computed Bindings
Thecomputed object maps prop names to named scripts from the scripts or scriptModules registry. The script is called with the current data context and its return value becomes the prop.
When to Use computed vs bindings
Use bindings when… | Use computed when… |
|---|---|
| The expression is simple and self-contained | The logic is complex or multi-step |
| The expression is only used in one place | The same logic is reused across multiple nodes |
| You want inline visibility of the logic | You want to name and document the logic |
Reactivity Model
V2 forms use Vue’s reactivity system under the hood. The data context is provided via Vue’sprovide/inject mechanism, and bindings are evaluated inside Vue computed properties. This means:
- Automatic updates: When
dataObjectsortagMetadataMapchange in the store, all bindings that reference them are automatically re-evaluated. - Efficient updates: Vue only re-evaluates bindings whose dependencies have changed. If a binding only reads
ctx.dataObjects[0].path, it will not re-evaluate when a different data object changes. - Synchronous evaluation: Binding expressions are evaluated synchronously. Async operations (API calls, etc.) should be performed in event handlers, not bindings.
Data Flow
Triggering Updates
The data context updates automatically when:- Data objects are added, removed, or modified in the workspace store
- Attributes are updated via the data attribute editor or via
kodexa.data.setAttribute - Tag metadata changes in the project store
Common Patterns
Conditional Display Based on Data
Default Values
Derived Styling
Combining Static Props with Bindings
Next Steps
Event Handling
Event types and handler configuration
Component Registry
Available components and how to register custom ones
