API documentation: https://resources.geocom.ch/VertiGIS/VertiGIS_Attribute_Form/1.5.0/interfaces/common_SchemaInterfaces.FormField.html
A FormField defines how a single feature attribute appears and behaves in your form. While FormField has many properties, only one is required: the field name.
When you specify just the field name, the Attribute Form automatically pulls metadata from your feature service/database:
•Field label (alias name)
•Data type: determines input control - text box, number, date picker, etc.
•Required/optional status
•Value domains: dropdown options
•Editability: read-only system fields
Add properties to override defaults, add validation, create dynamic behavior, or enhance the user experience.
Basic Configuration:
•name (mandatory): The feature field name this FormField represents
oExample: "diameter", "install_date", "owner_name"
oIf the name doesn't match any feature field, the FormField is hidden
•title (optional | default = field's alias/name from database): The label shown to users
oExample: "Pipe Diameter (inches)" instead of just "DIAM"
oSupports translation references: "@fieldDiameterLabel"
•tooltip (optional | default = undefined): Help text shown on hover
oExample: "Enter the measured diameter, not the nominal size"
oSupports translations: "@diameterTooltip"
Control Type:
•controlType (optional | default = auto-detected): Specifies the input control. Not all types work with all field data types.
oTextBox: Single-line text input
oTextArea: Multi-line text input (see rows property)
oText: Renders a read-only text display with no input element
oNumber: Numeric input with optional increment arrows
oCheckBox: Boolean checkbox (0 = unchecked, other values = checked)
oDatePicker: Date selector (no time)
oTimePicker: Time selector (no date)
oDateTimePicker: Date and time selector
oDropDownList: Dropdown menu (requires codedValues)
oRadioGroup: Radio button group (requires codedValues)
oCatalogPicker: Catalog selector (requires catalog)
oHorizontalRule: Internal element type; not directly configurable. Renders a horizontal line. Other properties have no effect, and the name can be set to “-”.
oLink: Formats an attribute value as a clickable link in the attribute form. Supports protocols such as http, https, and mailto to open websites or the default email client.
Hyperlinks and Link Protocols:
•linkProtocol (optional | default = undefined): Defines how a link is created when controlType is Link. If a protocol is already present in the attribute value, that protocol is used - unless it is considered harmful (e.g. javascript), in which case it is ignored. Possible values:
ohttp: Opens the URL as an HTTP web link.
ohttps: Opens the URL as an HTTPS web link.
ofile: Opens the URL as a file reference.
oftp: Opens the URL as an FTP link.
omailto: Opens the default email program with the stored address.
Catalog Integration:
•catalog (optional | default = undefined): Reference to the catalog to use
oOnly applicable when controlType is CatalogPicker
oExample: "@Pipetype"
•catalogColumnMapping (optional | default = undefined): Maps catalog columns to feature fields
oFormat: {"catalogColumnName": "featureFieldName"}
oUse case: Catalog uses generic names ("diameter") but your layer uses "PIPE_DIAM"
oSpecial cases:
▪Omit a catalog column to hide it
▪Map to empty string ("") to show in UI but not save to feature
•catalogColumnReference (optional | default = undefined): Display a catalog value without storing it
oScenario: Feature stores catalog ID but not all column values - use this to display additional catalog info
oProperties:
▪catalog: Which catalog to reference
▪catalogColumn: Which column's value to display
▪catalogKeyField: Feature field containing the catalog ID
oExample: Show "material description" based on stored "material_id"
Coded Values and Domains:
•codedValues (optional | default = undefined): Reference to a codedValues domain for dropdown/radio options
oOnly applicable with DropDownList or RadioGroup control types
oExample: "@CV_PipeMaterials"
oSee also: noValue property
•noValue (optional | default = "no value"): The label for the empty option in dropdowns/radio groups
oOnly appears when field is not required
oExample: "-- Select One --", "None", "Not Applicable"
oSupports translations: "@selectOneLabel"
Field Relationships:
•dependsOn (optional | default = undefined): Specifies a field that, when changed, triggers re-evaluation of this field
oPrimary use case: Dependent coded values (cascading dropdowns)
oExample: Material dropdown depends on Material Group
oWhen the referenced field changes, this field's options/value/validation are recalculated
See CodedValues section for implementation details
Calculated Fields:
•expression (optional | default = undefined): Reference to an Arcade expression that calculates this field's value
oCannot specify expression code directly - must reference a defined expression
oSyntax: Use {$expressionName} pattern
oMulti-expression text: Combine multiple expressions in one string
▪Example: "Total: {$sum} items of type {$category}"
oWith translations: Reference translated text containing expressions: "@translationKey"
oBehavior: Field automatically recalculates when any referenced field changes
oNote: Expression-based fields are automatically read-only
Field Behavior:
•enabled (optional | default = true): Controls whether the field is interactive
oBoolean: true or false
oArcade expression: "$feature.status != 'Completed'"
oImportant: Database-level read-only fields cannot be enabled via configuration
•readonly (optional | default = false): Makes the field read-only (disabled for editing)
oBoolean: true or false
oArcade expression: "$feature.approved == 1"
oUse case: Show field value but prevent modifications
•required (optional | default = from database nullable setting): Whether the field must have a value before saving
oBoolean: true or false
oArcade expression: "$feature.assetType == 10"
oExample: Make inspection date required only for completed inspections
•visible (optional | default = true): Controls field visibility
oBoolean: true or false
oArcade expression: "$feature.hasDamage == 1"
oExample: Only show repair cost field when damage is reported
Formatting Options:
•rows (optional | default = 3): Number of visible text lines for TextArea control type
oExample: 5 for description fields, 10 for detailed notes
•numberPrecision (optional | default = 3): Decimal places for Number control type
oExample: 2 for currency (10.25), 4 for precise measurements (3.1416)
•showThousandsSeparators (optional | default = true): Display commas in numbers (1,000 vs 1000)
oOnly applies to Number control type
oExample: false for ID numbers, true for population counts
•propertyType (optional | default = auto-detected): Explicitly specify the data type
oUsually auto-detected and doesn't need configuration
oUse when overriding automatic type detection
Validation:
•validation (optional | default = undefined): Custom validation rules beyond basic required/not-required
oexpression (optional): Arcade expression returning Boolean
▪Example: "$feature.endDate > $feature.startDate" (end after start)
omaxLength (optional): Maximum character count for TextBox or TextArea
▪Example: 50 for name fields, 500 for comments
oregex (optional): Regular expression pattern for text validation
▪Example: "^[A-Z]{2}\\d{4}$" for asset IDs like "AB1234"
orange (optional): Min/max values for Number fields
▪min (optional): Minimum acceptable value
▪max (optional): Maximum acceptable value
▪Example: Pressure rating between 0-200 PSI
omessage (optional): Custom error message when validation fails
▪Supports placeholders: {0}, {1}, {2} for dynamic values
▪Example: "Not in range: {0} must be between {1} and {2}"
▪Supports translations: "@validationErrorMessage"
Note: Required field validation is always enforced automatically.
Layout (Experimental):
•position (not yet fully supported | optional | default = undefined): Specify exact grid position
ocolumnIndex: Column number
orowIndex: Row number (counts across entire form including group headers)

A water utility needs a form for editing water valve features. The form should organize fields into groups, use translations, include validation, and show/hide fields based on conditions.
{
"schemas": {
"WaterValves": {
"title": "@valve_form_title",
"description": "**Important**: Changes to critical valves require supervisor approval",
"fieldTitleLocation": "above",
"readonly": "$feature.status == 'approved'",
"groups": [
{
"title": "@basic_information",
"format": "collapsible-section",
"collapsed": false,
"fields": [
{
"name": "objectid",
"title": "Valve ID",
"readonly": true
},
{
"name": "valve_name",
"title": "@field_valve_name",
"required": true,
"validation": {
"maxLength": 50,
"message": "@name_too_long_error"
}
},
{
"name": "valve_type",
"title": "@field_valve_type",
"controlType": "DropDownList",
"codedValues": "@CV_ValveTypes",
"required": true
},
{
"name": "install_date",
"title": "@field_install_date",
"controlType": "DatePicker",
"required": false
}
]
},
{
"title": "@specifications",
"format": "collapsible-section",
"collapsed": false,
"fields": [
{
"name": "diameter",
"title": "@field_diameter",
"controlType": "Number",
"numberPrecision": 2,
"showThousandsSeparators": false,
"required": true,
"validation": {
"range": {
"min": 1,
"max": 48
},
"message": "Diameter must be between 1 and 48 inches"
},
"tooltip": "Enter the nominal diameter in inches"
},
{
"name": "pressure_rating",
"title": "Pressure Rating (PSI)",
"controlType": "Number",
"numberPrecision": 0,
"showThousandsSeparators": true,
"required": true,
"validation": {
"range": {
"min": 0,
"max": 500
}
}
},
{
"name": "turns_to_close",
"title": "Turns to Close",
"controlType": "Number",
"numberPrecision": 1,
"visible": "$feature.valve_type == 10",
"tooltip": "Only applicable for gate valves"
}
]
},
{
"title": "@maintenance_info",
"format": "collapsible-section",
"collapsed": true,
"visible": "$feature.install_date != null",
"fields": [
{
"name": "last_inspection",
"title": "@field_last_inspection",
"controlType": "DatePicker",
"readonly": true
},
{
"name": "condition_rating",
"title": "@field_condition",
"controlType": "RadioGroup",
"codedValues": "@CV_ConditionRatings"
},
{
"name": "notes",
"title": "Inspection Notes",
"controlType": "TextArea",
"rows": 5,
"validation": {
"maxLength": 500
}
}
]
}
]
}
}
}
How this example works:
1.Form-level settings:
oUses translated title (@valve_form_title)
oShows Markdown description with important note
oLabels appear above fields
oEntire form becomes read-only when status is "approved"
2.Basic Information group:
oContains identification fields
oobjectid is read-only (system field)
ovalve_name is required with 50-character limit
ovalve_type uses a translated dropdown menu
oAll fields always visible
3.Specifications group:
oTechnical measurements with validation
odiameter must be 1-48 inches (custom error message)
opressure_rating shows thousands separators (e.g., "1,500")
oturns_to_close only visible for gate valves (valve_type == 10)
4.Maintenance Info group:
oInitially collapsed to reduce clutter
oGroup only visible if valve has installation date
olast_inspection is read-only (set by system)
ocondition_rating uses radio buttons
onotes allows 500 characters across 5 lines
This single configuration creates a smart, user-friendly form that adapts to data, validates input, and organizes information logically - all without custom code!