Declarative, JSON-serializable UI definitions with scripting, dynamic data binding, and conditional rendering
Data Forms V2 introduces a schema-driven approach to building form UIs in Kodexa. Instead of the card-based YAML configuration used in V1, V2 represents the entire form as a tree of UINode objects with scripting support, dynamic bindings, and a sandboxed Bridge API for interacting with platform data.
V1 Data Forms use a flat list of cards positioned on a 12-column grid. Each card type maps directly to a Vue component and is configured through YAML properties. This works well for dashboard-style layouts with grids, labels, and panels.V2 Data Forms use a tree of UINode objects stored as JSON. Each node references a registered component, declares props and bindings, and can contain children. The schema is fully JSON-serializable, which means it can be generated, validated, and transformed by backend services or AI agents without touching Vue code.
V2 forms can include inline expressions and reusable script modules. All scripts run in a QuickJS WebAssembly sandbox, isolated from the main browser context.
The Bridge API exposes platform capabilities to scripts and expressions through the kodexa.* namespaces. Each namespace requires explicit permissions declared in the form’s bridge configuration.
Permissions follow a least-privilege approach. A form must declare every capability it needs. If a script calls a method without the required permission, a Permission denied error is thrown.
Copy
Ask AI
{ "bridge": { "permissions": ["data:read"] }}
With this configuration, calling kodexa.data.setAttribute(...) would throw because data:write is not granted.
The permissions model is enforced client-side in the BridgeHost. Server-side API permissions still apply for http:get and http:post calls — the user’s session token determines what API endpoints are accessible.
The root SchemaRoot component provides the initial data context from the workspace store. When a node uses the for directive, each iteration creates a child context where $item is set to the current element and $parent points back to the enclosing context:
This scoping model means you can write bindings like ctx.$item.attributes without worrying about which specific data object you are operating on — the context handles it.
V1 and V2 forms share the same DataForm metadata object in the platform. The version is determined by inspecting the form definition:
Copy
Ask AI
function isDataFormV2(form: any): form is DataFormV2 { if (form.version === "2") return true; if (Array.isArray(form.nodes) && form.nodes.length > 0) return true; return false;}
A V2 form extends the base DataForm with additional fields:
Field
Type
Description
version
"1" | "2"
Explicit version flag
nodes
UINode[]
The V2 schema tree
scripts
Record<string, string>
Named inline scripts
scriptModules
Record<string, ScriptModule>
Reusable script modules with metadata
bridge
BridgeConfig
Bridge API configuration and permissions
When the platform renders a data form, it checks isDataFormV2() and routes to either the V1 card renderer or the V2 SchemaRoot component. Both renderers can coexist in the same project — you can have some forms using V1 cards and others using V2 schema nodes.
There is no automatic migration from V1 to V2. The two formats serve different use cases and can be used side by side within the same project.
V2 forms reference components by a string key (e.g., "kd:label", "kd:card-panel"). At startup, the platform registers all available components in a ComponentRegistry:
When SchemaNode encounters a component value, it resolves the component through the registry and dynamically renders it. This means V2 forms are not limited to a fixed set of card types — any registered component can be used.