Portal Community

ControlBinding Type

// packages/types-js/src/form.types.ts

interface ControlBinding {
  /** The data source to read from and write to */
  source:   '$json' | '$context';

  /** Dot-notation path within the source object */
  path:     string;

  /** If true: reads from source on load, but does NOT write back on change */
  readOnly?: boolean;

  /** Optional transform pair applied on read and write */
  transform?: {
    /** Applied when reading from the source — format for display */
    read?:  string;  // Named transform registered with registerBindingTransform()
    /** Applied when writing to the source — parse before save */
    write?: string;  // Named transform registered with registerBindingTransform()
  };
}

Minimal Binding

{
  "binding": {
    "source": "$json",
    "path":   "applicant.firstName"
  }
}

Read-Only Binding

// Shows the value but does not write it back when the user changes it
// Useful for displaying context data alongside editable fields
{
  "id":    "tenant-name",
  "type":  "label",
  "binding": {
    "source":   "$context",
    "path":     "tenant.displayName",
    "readOnly": true
  }
}

Binding With Transform

// Display a stored ISO date string (2026-01-15) as a localised date (15 Jan 2026)
// Parse the user's localised input back to ISO before saving
{
  "id":   "contract-date",
  "type": "date-picker",
  "binding": {
    "source": "$json",
    "path":   "contract.startDate",
    "transform": {
      "read":  "isoToLocaleDate",   // registered transform
      "write": "localeDateToIso"    // registered transform
    }
  }
}

Field Reference

FieldRequiredDefaultNotes
sourceYes$json or $context
pathYesDot-notation path; may include array indexing
readOnlyNofalseWhen true, user edits do not update the form's value map for this field
transform.readNoNamed transform applied when reading the raw value from source
transform.writeNoNamed transform applied when writing user input back to the value map

Controls Without a Binding

Omitting the binding property is valid and common for display-only controls (labels, dividers, articles, charts) and for controls whose values are not persisted (e.g., a search bar that filters an in-page list):

// No binding — value is local to the form and not submitted
{
  "id":   "search-filter",
  "type": "text",
  "placeholder": "Search..."
  // binding omitted: value held in form state but not written to any external path
}
No Binding ≠ No Value A control without a binding still participates in form state — its value is in engine.getValues() keyed by its id. It simply does not read from or write to an external path. Your submit handler can still read it from values['search-filter'].