Forms Step
Collect user input via an interactive form with text, email, phone, number, name, file upload, dropdowns, radio buttons, checkboxes, static content, and grouped layouts.
The Forms step presents users with an interactive form to collect structured data during a workflow. You define the form's components—fields, layout groups, and static content—and the values submitted become available for mapping in later steps. The step pauses workflow execution until the form is submitted. It can be used as the first step in a workflow and supports task assignment for notifying users.
Top-level configuration
| name | type | required | description |
|---|---|---|---|
type | string | no | Must be data-capture when provided. |
presentation | object | no | Form-level display settings. See Presentation below. |
components | array | yes | Ordered list of components defining the form's content and layout. |
taskAssignment | object | no | Controls how form completion notifications are delivered. See Task assignment below. |
logic | object | no | Conditional logic rules applied at the step level. |
Presentation
| name | type | required | description |
|---|---|---|---|
form.label | string | no | The form's display label (max 500 characters). |
form.submitLabel | string | no | Label for the submit button (max 255 characters, e.g. "Submit"). |
form.dateTimeConfig.offset | string | no | Timezone offset in +-HH:MM format (e.g. "+05:30", "-08:00"). Hours: -12 to +14, minutes: 00, 15, 30, or 45. |
Component types
A form is built from an ordered list of components. Each component has a type field that determines its behavior and available properties.
All field and presentation properties listed as form.* are nested under a presentation object in the component payload. For example, form.label maps to presentation.form.label in the JSON body.
Common component properties
Every component supports these base properties in addition to its type-specific ones:
| name | type | required | description |
|---|---|---|---|
id | string | no | Stable component id (UUID). Auto-generated if omitted. |
type | string | yes | The component type. |
label | string | no | Internal label. Used as the mapping label. |
readonly | boolean | no | Whether the field is read-only. Default: false. |
hidden | boolean | no | Whether the field is hidden from the form. Default: false. |
parentId | string | no | ID of the parent group component, if nested. |
logic | object | no | Conditional logic rules for this component. |
value | varies | no | Mapped value from a previous step. See Value and default value. |
defaultValue | varies | no | Pre-filled value set at design time. See Value and default value. |
Text
Use for single-line or multi-line text input, including formatted variants like email, phone, and ZIP.
| name | type | required | description |
|---|---|---|---|
type | string | yes | Must be text. |
validation.required | boolean | no | Whether input is mandatory. Default: false. |
validation.format | string | no | Input format constraint. One of: none, email, phone, ssn, url, zip, ein, numeric, alpha-numeric, alphabetic. |
validation.min | number | no | Minimum character length (>= 0). |
validation.max | number | no | Maximum character length (>= 0). Must be >= min when both are set. |
validation.errorMessage | string | no | Custom error message shown on validation failure (max 255 characters). |
validation.regexp | string | no | Custom regular expression for input validation. |
validation.countryCode | string | no | ISO 3166-1 alpha-2 country code (exactly 2 characters, e.g. "US", "BR"). Defaults to "US" when format is phone. |
validation.maskConfig | object | no | Input mask configuration. Contains mask (string) and definitions (key-value pairs mapping mask characters to regex patterns). |
validation.options | array | no | Predefined choices. See Option item. |
validation.optionsConfig | object | no | Options source config. See Options configuration below. |
form.label | string | yes | Human-readable field label (max 500 characters). |
form.type | string | no | Input control type: input, textarea, select, radio, or richtext. Default: input. |
form.placeholder | string | no | Placeholder text shown inside the input. |
form.helpText | string | no | Additional instructions shown below the field. |
form.textRows | number | no | Number of visible rows when form.type is textarea. |
validation.confirmation | object | no | Confirmation field config. When present, a second input renders and the user must re-enter the same value. See ConfirmationConfig. |
Number
Use for numeric input with optional range and format constraints.
| name | type | required | description |
|---|---|---|---|
type | string | yes | Must be number. |
readonly | boolean | no | Whether the field is read-only. Default: false. |
validation.required | boolean | no | Whether a value is mandatory. Default: false. |
validation.format | string | no | Numeric format: integer, decimal, currency, percentage, or regex. |
validation.min | number | no | Minimum allowed value (allows negative numbers). |
validation.max | number | no | Maximum allowed value. Must be >= min when both are set. |
validation.regex | string | no | Custom regex pattern. Required when format is regex. |
form.label | string | yes | Human-readable field label (max 500 characters). |
form.type | string | no | Must be input. Default: input. |
form.placeholder | string | no | Example numeric value shown as placeholder. |
form.helpText | string | no | Additional instructions shown below the field. |
form.locales | string | no | Locale string for number formatting (max 10 characters, e.g. "en-US"). |
form.numberFormat | object | no | Number display format configuration. |
form.numberFormat.style | string | no | Format style: decimal, currency, percent, or unit. |
form.numberFormat.currency | string | no | ISO 4217 currency code (e.g. "USD", "EUR"). Used when style is currency. |
form.numberFormat.minimumFractionDigits | number | no | Minimum number of decimal places to display. |
Dropdown
Use for single-select input rendered as a dropdown/select control.
| name | type | required | description |
|---|---|---|---|
type | string | yes | Must be dropdown. |
validation.required | boolean | no | Whether a selection is mandatory. Default: false. |
validation.options | array | no | Predefined choices. See Option item. |
validation.errorMessage | string | no | Custom error message (max 255 characters). |
form.label | string | yes | Human-readable field label (max 500 characters). |
form.type | string | yes | Must be select. |
form.placeholder | string | no | Placeholder text for the dropdown. |
form.helpText | string | no | Additional instructions shown below the field. |
Radio
Use for single-select input rendered as a radio button group.
| name | type | required | description |
|---|---|---|---|
type | string | yes | Must be radio. |
validation.required | boolean | no | Whether a selection is mandatory. Default: false. |
validation.format | string | no | Inherits text validation formats (typically unused for radio). |
validation.min | number | no | Minimum character length. |
validation.max | number | no | Maximum character length. |
validation.options | array | no | Predefined choices. See Option item. |
validation.errorMessage | string | no | Custom error message (max 255 characters). |
validation.optionsConfig | object | no | Options source config. See Options configuration below. |
form.label | string | yes | Human-readable field label (max 500 characters). |
form.type | string | yes | Must be radio. |
form.placeholder | string | no | Placeholder text. |
form.helpText | string | no | Additional instructions shown below the field. |
List (checkbox)
Use for multi-select input rendered as a checkbox group.
| name | type | required | description |
|---|---|---|---|
type | string | yes | Must be list. |
validation.required | boolean | no | Whether at least one selection is mandatory. Default: false. |
validation.options | array | no | Predefined choices. Minimum 1 item when provided. See Option item. |
validation.errorMessage | string | no | Custom error message (max 255 characters). |
validation.optionsConfig | object | no | Options source config. See Options configuration below. |
form.label | string | yes | Human-readable field label (max 500 characters). |
form.type | string | yes | Must be checkbox. |
form.placeholder | string | no | Placeholder text. |
form.helpText | string | no | Additional instructions shown below the field. |
form.allowCheckAll | boolean | no | Show a "check all" toggle. Default: false. |
Email
Use for email address input. Extends the Text component with a fixed email type and enforced email format validation.
| name | type | required | description |
|---|---|---|---|
type | string | yes | Must be email. |
defaultValue | string | no | Default email address to pre-fill. |
validation.required | boolean | no | Whether input is mandatory. Default: false. |
validation.format | string | no | Inherited from text. Typically set to email automatically. |
validation.min | number | no | Minimum character length (>= 0). |
validation.max | number | no | Maximum character length (>= 0). Must be >= min when both are set. |
validation.errorMessage | string | no | Custom error message (max 255 characters). |
form.label | string | yes | Human-readable field label (max 500 characters). |
form.type | string | no | Input control type. Default: input. |
form.placeholder | string | no | Placeholder text (e.g. "[email protected]"). |
form.helpText | string | no | Additional instructions shown below the field. |
validation.confirmation | object | no | Confirmation field config. When present, a second input renders and the user must re-enter the same value. See ConfirmationConfig. |
ConfirmationConfig
Applies to text and email components (email and short answer formats). When validation.confirmation is present, a second input renders below the original field and the form blocks submission until both values match. An empty {} enables confirmation with default labels.
| name | type | required | description |
|---|---|---|---|
label | string | no | Label above the confirmation input. Defaults to "Confirm email" or "Confirm answer". |
placeholder | string | no | Placeholder text for the confirmation input. |
helpText | string | no | Helper text displayed near the confirmation input. |
All properties are nullable — set to null to explicitly clear a default.
Phone
Use for phone number input. Extends the Text component with phone-specific validation and a country code that defaults to "US".
| name | type | required | description |
|---|---|---|---|
type | string | yes | Must be phone. |
defaultValue | string | no | Default phone number to pre-fill. |
validation.required | boolean | no | Whether input is mandatory. Default: false. |
validation.min | number | no | Minimum character length (>= 0). |
validation.max | number | no | Maximum character length (>= 0). Must be >= min when both are set. |
validation.countryCode | string | no | ISO 3166-1 alpha-2 country code (exactly 2 characters). Defaults to "US". |
validation.errorMessage | string | no | Custom error message (max 255 characters). |
validation.options | array | no | Predefined choices. See Option item. |
form.label | string | yes | Human-readable field label (max 500 characters). |
form.type | string | yes | Must be input. |
form.format | string | no | Presentation format hint. Defaults to phone. |
form.placeholder | string | no | Placeholder text (e.g. "(555) 123-4567"). |
form.helpText | string | no | Additional instructions shown below the field. |
Name part
Use for individual parts of a name field. Must be nested inside a Group with subType set to name and form.type set to full_name. A name group always contains first and last name parts by default. Optional parts are prefix, suffix, middle, and middle_initial. The middle and middle_initial parts are mutually exclusive—only one can be present at a time.
Each name part uses a groupId to identify its role within the name group: first, last, middle, middle_initial, prefix, or suffix.
When making a name field required, set validation.required: true on both the parent name group and each child name part.
| name | type | required | description |
|---|---|---|---|
type | string | yes | Must be name_part. |
groupId | string | no | Role within the name group: first, last, middle, middle_initial, prefix, or suffix. |
defaultValue | string | no | Default value to pre-fill. |
validation.required | boolean | no | Whether input is mandatory. Default: false. |
validation.min | number | no | Minimum character length (>= 0). |
validation.max | number | no | Maximum character length (>= 0). Must be >= min when both are set. |
validation.errorMessage | string | no | Custom error message (max 255 characters). |
form.label | string | yes | Human-readable field label (max 500 characters, e.g. "First Name"). |
form.type | string | no | Input control type. Default: input. |
form.placeholder | string | no | Placeholder text. |
form.helpText | string | no | Additional instructions shown below the field. |
File upload
Use to accept file attachments from users. Supports restricting allowed file extensions and enforcing file size limits up to 2 GB.
| name | type | required | description |
|---|---|---|---|
type | string | yes | Must be file_upload. |
validation.required | boolean | no | Whether at least one file is required. Default: false. |
validation.min | number | no | Minimum file size in bytes (>= 0, max 2 GB). |
validation.max | number | no | Maximum file size in bytes (>= 0, max 2 GB). Must be >= min when both are set. |
fileConfig | object | no | File type restrictions. |
fileConfig.types | array | no | Allowed file extensions (e.g. ["pdf", "docx", "png"]). Minimum 1 item when provided. When omitted, all non-blocked file types are accepted. Blocked extensions include executables (.exe, .app, .dmg), scripts (.bat, .cmd, .js, .vbs, .ps1), installers (.msi, .deb, .rpm), macro-enabled Office files (.dotm, .xlsm, .pptm), and other potentially dangerous formats. Duplicate extensions are also rejected. |
form.label | string | yes | Human-readable field label (max 500 characters). |
form.type | string | no | Must be input. |
form.placeholder | string | no | Placeholder text. |
form.helpText | string | no | Additional instructions shown below the field. |
Address group
Use to collect a structured address. The presentation.form.addressFormat property (ISO 3166-1 alpha-2 country code, default "US") controls country-specific behavior for labels, state/province options, and postal code validation.
An address group always contains these sub-fields, each identified by groupId:
address_line_1— Street address line 1 (type: "address_line")address_line_2— Street address line 2 (type: "address_line")city— City (type: "address_city")state— State/Province/Region (type: "address_state")postal_code— ZIP/Postal code (type: "address_postal_code")country— Country (type: "address_country")
Individual sub-fields can be hidden by setting hidden: true, but at least one must remain visible.
| name | type | required | description |
|---|---|---|---|
type | string | yes | Must be address_group. |
validation.required | boolean | no | Whether the address is required. When set, also set validation.required on each child sub-field. |
form.label | string | yes | Human-readable label (max 500 characters). |
form.type | string | yes | Must be address. |
form.addressFormat | string | no | ISO 3166-1 alpha-2 country code (e.g. "US", "CA", "GB", "AU"). Default: "US". Controls state/province options and postal code validation. |
components | array | no | Address sub-field components (see below). |
Address sub-field types
All address sub-fields extend the Text component and accept a single string value. Each uses a groupId to identify its role.
Address line (type: "address_line")
Text input for street address. Typically two instances: groupId: "address_line_1" and groupId: "address_line_2".
City (type: "address_city")
Text input for the city name.
State (type: "address_state")
Extends Dropdown when the country has a known state/province list, or renders as a plain text input otherwise.
| Country | Preset category | Renders as |
|---|---|---|
| US | state-names or state-abbreviations | dropdown |
| AU | australian-states | dropdown |
| CA | canadian-provinces | dropdown |
| GB | uk-provinces | dropdown |
| Other | none | text input |
Set presentation.form.type to select and use validation.optionsConfig with source: "preset" to configure the preset. For countries without a preset, use presentation.form.type: "input".
Postal code (type: "address_postal_code")
Text input with optional mask and regex validation. Only US addresses have postal code presets:
| Preset category | Mask | Regex pattern | Example |
|---|---|---|---|
zip-standard | 00000 | ^\d{5}$ | 90210 |
zip-plus4 | 00000-0000 | ^\d{5}-\d{4}$ | 90210-1234 |
For US addresses, set presentation.form.maskConfig with mask and definitions (e.g. {"0": "[0-9]"}), and validation.regexp for server-side validation. For non-US addresses, the postal code is a plain text input with no mask or regex.
Country (type: "address_country")
Extends Dropdown. Uses the country-names preset (ISO 3166-1 alpha-2 list of all countries). By default, the country field is hidden: true and readonly: true with defaultValue set to the addressFormat value (e.g. "US"). To allow users to select a country, set hidden: false and readonly: false.
Date
Use for date input with a calendar or dropdown picker.
| name | type | required | description |
|---|---|---|---|
type | string | yes | Must be date. |
validation.required | boolean | no | Whether a date is mandatory. Default: false. |
validation.dateTimeConfig | object | no | Date range constraints. See Date range validation. |
form.label | string | yes | Human-readable field label (max 500 characters). |
form.placeholder | string | no | Placeholder text. |
form.helpText | string | no | Additional instructions shown below the field. |
form.dateTimeConfig | object | no | Date display configuration. See DateTime configuration. Uses: dateFormat, useCurrentDate, displayView (calendar or dropdown), offset. |
Time
Use for time input with a time picker or dropdown.
| name | type | required | description |
|---|---|---|---|
type | string | yes | Must be time. |
validation.required | boolean | no | Whether a time is mandatory. Default: false. |
form.label | string | yes | Human-readable field label (max 500 characters). |
form.placeholder | string | no | Placeholder text. |
form.helpText | string | no | Additional instructions shown below the field. |
form.dateTimeConfig | object | no | Time display configuration. See DateTime configuration. Uses: timeFormat, useCurrentTime, displayView (time_picker or dropdown), timeIncrement, offset. |
DateTime
Use for combined date and time input.
| name | type | required | description |
|---|---|---|---|
type | string | yes | Must be datetime. |
validation.required | boolean | no | Whether a value is mandatory. Default: false. |
validation.dateTimeConfig | object | no | Date range constraints. See Date range validation. |
form.label | string | yes | Human-readable field label (max 500 characters). |
form.placeholder | string | no | Placeholder text. |
form.helpText | string | no | Additional instructions shown below the field. |
form.dateTimeConfig | object | no | Date and time display configuration. See DateTime configuration. Uses: dateFormat, timeFormat, useCurrentDate, useCurrentTime, displayView (calendar or dropdown), timeIncrement, offset. |
For datetime components, defaultValue cannot be set when both useCurrentDate and useCurrentTime are enabled.
DateTime configuration
The form.dateTimeConfig object controls display and behavior for temporal components. Not all properties apply to every component type—each component lists which properties it uses.
| name | type | applies to | description |
|---|---|---|---|
dateFormat | string | date, datetime | Display format for the date part (ICU pattern). See Allowed date formats. |
timeFormat | string | time, datetime | Display format for the time part (ICU pattern). See Allowed time formats. |
useCurrentDate | boolean | date, datetime | Pre-fill with the current date. Cannot be used with defaultValue. |
useCurrentTime | boolean | time, datetime | Pre-fill with the current time. Cannot be used with defaultValue. |
displayView | string | all | Picker style. date/datetime: calendar or dropdown. time: time_picker or dropdown. |
timeIncrement | number | time, datetime | Minute interval for time selection (1–60). |
offset | string | all | Timezone offset in +-HH:MM format (e.g. "+05:30", "-08:00"). |
Date range validation
The validation.dateTimeConfig.dateRange object constrains allowed dates for date and datetime components.
| name | type | required | description |
|---|---|---|---|
start | string | no | Earliest allowed date (ISO 8601 datetime, e.g. "2026-04-01T00:00:00.000Z"). |
end | string | no | Latest allowed date (ISO 8601 datetime). Must be >= start when both are set. |
Datetime value format
All temporal components store their value as an object:
| name | type | required | description |
|---|---|---|---|
utc | string | yes | ISO 8601 datetime string (e.g. "2025-10-21T13:00:00Z"). |
offset | string | no | Timezone offset in +-HH:MM format, or "UnknownOffset". |
format | string | no | ICU format string used for display. |
formatValue | string | no | The UTC value formatted using the format string. |
Allowed date formats
| Format | Example |
|---|---|
MM/dd/yy | 10/21/25 |
MM/dd/yyyy | 10/21/2025 |
MMM d, yyyy | Oct 21, 2025 |
MMMM d, yyyy | October 21, 2025 |
EEEE, MMMM d, yyyy | Tuesday, October 21, 2025 |
dd/MM/yy | 21/10/25 |
dd/MM/yyyy | 21/10/2025 |
dd MMM yyyy | 21 Oct 2025 |
dd MMMM yyyy | 21 October 2025 |
yy-MM-dd | 25-10-21 |
yyyy-MM-dd | 2025-10-21 |
MMM yyyy | Oct 2025 |
Allowed time formats
| Format | Example | Description |
|---|---|---|
HH:mm | 13:30 | 24-hour with leading zero |
HH:mm:ss | 13:30:00 | 24-hour with seconds |
h:mm a | 1:30 PM | 12-hour without leading zero |
hh:mm a | 01:30 PM | 12-hour with leading zero |
h:mm:ss a | 1:30:00 PM | 12-hour with seconds, no leading zero |
hh:mm:ss a | 01:30:00 PM | 12-hour with seconds and leading zero |
Static content
Use to display non-interactive content such as headings, instructions, dividers, or formatted HTML/Markdown.
| name | type | required | description |
|---|---|---|---|
type | string | yes | Must be static_content. |
form.type | string | yes | Display variant: heading, html, md, or divider. |
form.label | string | yes | Human-readable label (max 500 characters). |
form.content | string | no | Body content. For heading, this is the heading text. Required for html type. HTML content must contain valid HTML tags, and cannot include <script> tags or event handler attributes for security. |
form.level | number | no | Heading level when form.type is heading: 1 (H1), 2 (H2), or 3 (H3). |
form.textAlign | string | no | Text alignment when form.type is heading: left, center, or right. |
Group
Use to arrange components into pages, sections, or grid layouts, and to define composite field types like Name. A group component placed directly in the top-level components array (without a parentId) acts as a page. All field components must be nested inside a page group.
| name | type | required | description |
|---|---|---|---|
type | string | yes | Must be group. |
subType | string | no | Group variant. Set to name for name groups (used with form.type: full_name). |
validation.required | boolean | no | Whether the group is required. When making a group required, also set validation.required on each child component. |
form.label | string | yes | Human-readable label (max 500 characters). |
form.type | string | yes | Layout mode: full_name, grid, group, none, page, or section. |
form.gridOptions | array | no | Grid position hints for nested components. Each item requires gridColumnStart, gridColumnEnd, gridRowStart, gridRowEnd (all strings). |
components | array | no | Nested components within the group. |
Logic (conditional rules)
Logic rules allow you to dynamically control form behavior based on field values. Rules are evaluated in real time as users fill out the form. Logic can be defined at the step level (logic on the top-level config) or on individual components.
A logic object contains an array of logicRules. Each rule has a condition (what to evaluate) and an array of actions (what to do when the condition is true).
| name | type | required | description |
|---|---|---|---|
logicRules | array | yes | Array of logic rules. |
Logic rule
Condition
Conditions can be leaf nodes (a single comparison rule) or branch nodes (nested conditions combined with and/or logic). Nesting depth is limited to 5 levels.
| name | type | required | description |
|---|---|---|---|
id | string | yes | Unique condition identifier (UUID). |
rule | object | no | A single comparison rule (leaf condition). See Condition rule. |
conditions | array | no | Nested conditions (branch condition). Each item is a Condition object. |
mode | string | no | How to combine nested conditions: and or or. |
A condition is a leaf when it has a rule and no conditions. It is a branch when it has conditions (and typically a mode).
Condition rule
A condition rule compares a left-hand expression against a right-hand expression using an operator. The type determines which operators are valid.
| name | type | required | description |
|---|---|---|---|
id | string | yes | Unique rule identifier (UUID). |
type | string | yes | Comparison type. See Condition rule types. |
leftHandExpression | object | yes | The value to test. See Expression. |
operator | string | yes | The comparison operator. See Operators. |
rightHandExpression | object | yes | The value to compare against. See Expression. |
Condition rule types
| Type | Description | Valid operators |
|---|---|---|
string_comparison | Compare text values | is, is_not, is_empty, is_not_empty, contains, does_not_contain, starts_with, does_not_start_with, ends_with, does_not_end_with, is_longer_than, is_not_longer_than, is_shorter_than, is_not_shorter_than, is_longer_or_equal_to, is_not_longer_or_equal_to, is_shorter_or_equal_to, is_not_shorter_or_equal_to |
number_comparison | Compare numeric values | is, is_not, is_empty, is_not_empty, is_greater_than, is_less_than, is_greater_than_or_equal_to, is_less_than_or_equal_to |
date_comparison | Compare date/time values | is, is_not, is_empty, is_not_empty, is_after, is_before, is_within, is_not_within |
list_comparison | Compare list/checkbox values | is, is_not, is_empty, is_not_empty, contains, does_not_contain |
always_true | Always evaluates to true | any |
always_false | Always evaluates to false | any |
Expression
An expression provides the value for one side of a condition rule comparison.
| name | type | required | description |
|---|---|---|---|
type | string | yes | Expression type. See below. |
value | string | yes | The expression value (template string or literal). |
dataMappingType | string | no | Component type hint for data-mapped expressions. |
Expression types:
| Type | Description | Example value |
|---|---|---|
literal_template | A static literal value to compare against. | "show", "100", "US" |
field_template | References a field's current value. Uses the step description and the component UUID. | "{{`Form (new)`.`findComponentValueById.ad47b60e-...`}}" |
arithmetic_template | An arithmetic expression combining field references. | "{{`Form (new)`.`findComponentValueById.uuid1`}} + {{`Form (new)`.`findComponentValueById.uuid2`}}" |
data_mapped_value | References a value from workflow data mapping. | Mapping template string |
Template reference functions:
Expression templates use backtick-wrapped references with the step description and a lookup function. Three reference functions are available:
| Function | Purpose | Template format |
|---|---|---|
findComponentValueById.<componentId> | Reference a field's current value by component UUID. | {{`<step description>`.`findComponentValueById.<UUID>`}} |
findOptionById.<optionId> | Reference a specific option's value by option UUID. Used for inline (non-preset) options. | {{`<step description>`.`findOptionById.<UUID>`}} |
findStaticOptionByCategoryAndId.<category>.<value> | Reference a preset option by category and value. Used for preset options (e.g. state names, countries). | {{`<step description>`.`findStaticOptionByCategoryAndId.<category>.<value>`}} |
Action
An action defines what happens when a logic rule's condition evaluates to true.
| name | type | required | description |
|---|---|---|---|
id | string | no | Action identifier (UUID). |
type | string | yes | Action type: component_action, disable_submission, or theme_action. |
componentAction | object | no | Required when type is component_action. See Component action. |
themeAction | object | no | Required when type is theme_action. Contains type (modify), key, and value. |
When type is disable_submission, no additional configuration is needed—the submit button is disabled.
Component action
A component action modifies a specific component when triggered.
| name | type | required | description |
|---|---|---|---|
type | string | yes | The action to perform. See Component action types. |
componentId | string | yes | ID of the target component. |
modifyConfig | object | no | Required for modify. Contains key (property path) and value. |
excludeConfig | object | no | Required for exclude. Empty object. |
valueConfig | object | no | Required for value. Contains an expression object. |
Component action types
| Type | Description | Requires config |
|---|---|---|
show | Make the component visible. | none |
hide | Hide the component. | none |
show_and_include | Show the component and include its value in submission. | none |
hide_and_exclude | Hide the component and exclude its value from submission. | none |
exclude | Exclude the component's value from submission (without hiding). | excludeConfig |
make_required | Make the component required. | none |
make_optional | Make the component optional. | none |
make_read_only | Make the component read-only. | none |
make_editable | Make the component editable. | none |
modify | Modify a component property directly. | modifyConfig |
value | Set the component's value via an expression. | valueConfig |
Logic example
Logic examples
Condition: show a section when department is "Engineering"
A simple string comparison condition with a show action. The section starts as hidden: true and becomes visible when the dropdown value matches.
{
"id": "rule-show-section",
"name": "Show engineering details",
"condition": {
"id": "cond-1",
"rule": {
"id": "rule-1",
"type": "string_comparison",
"operator": "is",
"leftHandExpression": {
"type": "field_template",
"value": "{{`Job Application`.`findComponentValueById.030d8c25-9133-4ab7-9dfe-f00cce153565`}}",
"dataMappingType": "dropdown"
},
"rightHandExpression": {
"type": "literal_template",
"value": "engineering"
}
}
},
"actions": [
{
"type": "component_action",
"componentAction": {
"type": "show",
"componentId": "engineering-section-id"
}
}
]
}Action: hide and exclude from submission
When country is "US", hide the international section and exclude its data from the submitted values.
{
"type": "component_action",
"componentAction": {
"type": "hide_and_exclude",
"componentId": "international-section-id"
}
}Action: make a field required
Make the phone field required when work arrangement is "On-site".
{
"type": "component_action",
"componentAction": {
"type": "make_required",
"componentId": "53839acd-f783-43a0-9212-d33e8d926e45"
}
}Action: set a field value from another field
Copy the email value into a read-only confirmation field using value action with a field_template expression.
{
"type": "component_action",
"componentAction": {
"type": "value",
"componentId": "confirmation-email-id",
"valueConfig": {
"expression": {
"type": "field_template",
"value": "{{`Job Application`.`findComponentValueById.ad47b60e-9098-4f1f-9d19-9fb46ae242af`}}",
"dataMappingType": "email"
}
}
}
}Action: disable form submission
Prevent the user from submitting the form when a condition is met. No additional configuration is needed.
{
"type": "disable_submission"
}Options configuration
Components that support predefined choices (text, radio, list) can use validation.optionsConfig to control the source of their options.
| name | type | required | description |
|---|---|---|---|
customOptionId | string | no | ID of a custom "other" option that allows free-text input. |
source | string | no | Where options come from: field-options (inline list) or preset (built-in list). |
preset | object | no | Preset reference when source is preset. |
preset.category | string | yes | Preset category. See Option presets. |
preset.id | string | yes | Preset identifier. |
Option item
Each item in a validation.options array has this shape:
| name | type | required | description |
|---|---|---|---|
id | string | no | Option identifier. |
label | string | yes | Display label. |
value | string | yes | Stored value. |
Option presets
Built-in option lists available via validation.optionsConfig.preset.category:
| Category | Used by | Description |
|---|---|---|
state-names | address_state | U.S. state full names (e.g. "California") |
state-abbreviations | address_state | U.S. state 2-letter codes (e.g. "CA") |
australian-states | address_state | Australian state/territory names |
canadian-provinces | address_state | Canadian province/territory names |
uk-provinces | address_state | UK county/region names |
country-names | address_country | All countries (ISO 3166-1 alpha-2 codes and names) |
zip-standard | address_postal_code | U.S. 5-digit ZIP code mask and validation |
zip-plus4 | address_postal_code | U.S. ZIP+4 (9-digit) mask and validation |
Value and default value
Components can be pre-filled using value or defaultValue. value is populated at runtime from workflow mapping (data from a previous step), while defaultValue is set at design time in the builder. When both are present, value takes precedence. The accepted shape depends on the component type:
| Component type | value / defaultValue type | Example |
|---|---|---|
text, email, phone, name_part | string | "John" |
text (with options via select) | string or array of strings | "option1" or ["option1", "option2"] |
number | number | 42 |
dropdown, radio | string | "engineering" |
list | array of strings | ["health", "retirement"] |
date, time, datetime | datetime value object | {"utc": "2026-04-01T00:00:00.000Z"} |
file_upload | file object | {"id": "file-uuid", "source": ...} |
address_line, address_city, address_state, address_postal_code | string | "90210" |
address_country | string (ISO country code) | "US" |
For date, time, and datetime components, defaultValue cannot be set when useCurrentDate or useCurrentTime is enabled. See Datetime value format for the value object shape.
File upload currently accepts only one file per component. The submitted value is normalized to an array of file IDs. When fileConfig.types is not set, all non-blocked file types are accepted.
Task assignment
The taskAssignment property controls how form completion notifications are delivered to users. It uses a discriminated union on type.
| name | type | required | description |
|---|---|---|---|
type | string | yes | email, phone, or inheritFromPreviousStep. |
name | string | yes (if type is email or phone) | Assignment name. |
config | object | yes (if type is email or phone) | Delivery configuration. |
When type is inheritFromPreviousStep, no other properties are needed.
Email assignment config
| name | type | required | description |
|---|---|---|---|
recipients | array(string) | yes | Email addresses to notify. |
from | string | no | Sender email address. |
replyTo | string | no | Reply-to email address. |
subject | string | yes | Email subject line. |
message | string | yes | Email body. |
buttonLabel | string | yes | Label for the action button in the email. |
Phone assignment config
| name | type | required | description |
|---|---|---|---|
recipients | array(string) | yes | Phone numbers to notify. |
message | string | yes | SMS message text. |
Examples
A minimal form containing a single text field. All fields must be nested inside a page group—a group component placed at the top level of the components array acts as a page.
{
"type": "data-capture",
"presentation": {
"form": {
"label": "Contact Form",
"submitLabel": "Submit"
}
},
"components": [
{
"id": "835b17f8-f133-434e-a8d1-b43e1249557d",
"type": "group",
"label": "Page",
"components": [
{
"id": "5db1b7be-479d-4a35-912c-9558e9ff1db3",
"type": "text",
"label": "email_address",
"parentId": "835b17f8-f133-434e-a8d1-b43e1249557d",
"validation": {
"required": true,
"format": "email",
"confirmation": {
"label": "Confirm email",
"placeholder": "[email protected]",
"helpText": "Re-enter your email to confirm."
}
},
"presentation": {
"form": {
"label": "Email Address",
"type": "input",
"placeholder": "[email protected]"
}
}
}
]
}
]
}A fuller form showcasing all documented component types across two pages with conditional logic. Page 1 (Contact Information) starts with a heading, followed by name, email, phone, resume upload, and a US address inside a section. Page 2 (Role Preferences) contains years of experience, department, work arrangement, benefits (hidden by default), temporal fields, and a terms block. Three logic rules demonstrate: making phone required when on-site is selected, showing benefits when department is Engineering, and disabling submission when experience is 0:
{
"type": "data-capture",
"presentation": {
"form": {
"label": "Job Application",
"submitLabel": "Submit"
}
},
"components": [
{
"id": "edbde9cd-5b03-4c8e-aaa8-71e415e78d13",
"type": "group",
"label": "Contact Information",
"components": [
{
"id": "57c31542-2aac-4b98-b114-f547857108c3",
"type": "static_content",
"label": "",
"parentId": "edbde9cd-5b03-4c8e-aaa8-71e415e78d13",
"presentation": {
"form": {
"type": "heading",
"label": "Job Application",
"content": "Please fill out the form below to apply for an open position.",
"textAlign": "left",
"level": 1
}
}
},
{
"id": "350d39fb-1223-48eb-9913-6e778b582c9b",
"type": "group",
"label": "Contact informations",
"parentId": "edbde9cd-5b03-4c8e-aaa8-71e415e78d13",
"components": [
{
"id": "c09c4caa-fcdb-4f0d-b163-e60e56a2c282",
"type": "group",
"label": "",
"subType": "name",
"parentId": "350d39fb-1223-48eb-9913-6e778b582c9b",
"validation": {
"required": true
},
"components": [
{
"id": "86930da3-4a09-4e9d-81ce-64666a15d13e",
"type": "name_part",
"label": "",
"groupId": "first",
"parentId": "c09c4caa-fcdb-4f0d-b163-e60e56a2c282",
"validation": {
"required": true
},
"presentation": {
"form": {
"type": "input",
"label": "First name",
"helpText": "First name"
}
}
},
{
"id": "6e362adf-e2dd-43c5-92c4-49f3526edcfe",
"type": "name_part",
"label": "",
"groupId": "last",
"parentId": "c09c4caa-fcdb-4f0d-b163-e60e56a2c282",
"validation": {
"required": true
},
"presentation": {
"form": {
"type": "input",
"label": "Last name",
"helpText": "Last name"
}
}
}
],
"presentation": {
"form": {
"type": "full_name",
"label": "Name"
}
}
},
{
"id": "ad47b60e-9098-4f1f-9d19-9fb46ae242af",
"type": "email",
"label": "",
"parentId": "350d39fb-1223-48eb-9913-6e778b582c9b",
"validation": {
"format": "email",
"required": true
},
"presentation": {
"form": {
"type": "input",
"label": "Email",
"placeholder": "[email protected]"
}
}
},
{
"id": "53839acd-f783-43a0-9212-d33e8d926e45",
"type": "phone",
"label": "",
"parentId": "350d39fb-1223-48eb-9913-6e778b582c9b",
"validation": {
"required": false,
"countryCode": "US"
},
"presentation": {
"form": {
"type": "input",
"label": "Phone",
"placeholder": "(000) 000-0000"
}
}
},
{
"id": "81412186-9341-41b2-90df-186eea0a58b5",
"type": "file_upload",
"label": "",
"parentId": "350d39fb-1223-48eb-9913-6e778b582c9b",
"fileConfig": {
"types": ["pdf", "docx"]
},
"validation": {
"required": false
},
"presentation": {
"form": {
"type": "input",
"label": "Upload Resume"
}
}
},
{
"id": "6b466657-622f-4d69-ac9a-df091fb85495",
"type": "address_group",
"label": "",
"parentId": "350d39fb-1223-48eb-9913-6e778b582c9b",
"validation": {
"required": false
},
"components": [
{
"id": "d86d0f8f-901e-4cb2-b4e4-efafeecc3c76",
"type": "address_line",
"label": "",
"groupId": "address_line_1",
"parentId": "6b466657-622f-4d69-ac9a-df091fb85495",
"validation": {
"format": "none",
"required": false
},
"presentation": {
"form": {
"type": "input",
"label": "Address Line 1",
"helpText": "Address Line 1"
}
}
},
{
"id": "38bef146-0b06-4d7a-84dc-78a23bc742a2",
"type": "address_line",
"label": "",
"groupId": "address_line_2",
"parentId": "6b466657-622f-4d69-ac9a-df091fb85495",
"validation": {
"format": "none",
"required": false
},
"presentation": {
"form": {
"type": "input",
"label": "Address Line 2",
"helpText": "Address Line 2"
}
}
},
{
"id": "182f8268-b4bc-4f4d-84f2-a09d20015155",
"type": "address_city",
"label": "",
"groupId": "city",
"parentId": "6b466657-622f-4d69-ac9a-df091fb85495",
"validation": {
"format": "none",
"required": false
},
"presentation": {
"form": {
"type": "input",
"label": "City",
"helpText": "City"
}
}
},
{
"id": "112d34e9-e314-4add-a0fc-243f586755c9",
"type": "address_state",
"label": "",
"groupId": "state",
"parentId": "6b466657-622f-4d69-ac9a-df091fb85495",
"validation": {
"required": false,
"optionsConfig": {
"source": "preset",
"preset": {
"id": "preset-us-states",
"category": "state-names"
}
}
},
"presentation": {
"form": {
"type": "select",
"label": "State",
"helpText": "State"
}
}
},
{
"id": "ac4d9d1a-dde0-435a-93be-cd707a88afcc",
"type": "address_postal_code",
"label": "",
"groupId": "postal_code",
"parentId": "6b466657-622f-4d69-ac9a-df091fb85495",
"validation": {
"format": "none",
"required": false,
"regexp": "^\\d{5}$"
},
"presentation": {
"form": {
"type": "input",
"label": "ZIP Code",
"helpText": "ZIP Code",
"maskConfig": {
"mask": "00000",
"definitions": {
"0": "[0-9]"
}
}
}
}
},
{
"id": "ea3ad46c-c6c6-4e64-aa0e-a783a9b37189",
"type": "address_country",
"label": "",
"groupId": "country",
"parentId": "6b466657-622f-4d69-ac9a-df091fb85495",
"readonly": true,
"hidden": true,
"defaultValue": "US",
"validation": {
"optionsConfig": {
"source": "preset",
"preset": {
"id": "preset-countries",
"category": "country-names"
}
}
},
"presentation": {
"form": {
"type": "select",
"label": "Country",
"helpText": "Country"
}
}
}
],
"presentation": {
"form": {
"type": "address",
"label": "Address",
"addressFormat": "US"
}
}
}
],
"presentation": {
"form": {
"type": "section",
"label": "Contact Information"
}
}
}
]
},
{
"id": "d407e894-d8e7-419d-8462-5bf361e3083d",
"type": "group",
"label": "Role Preferences",
"components": [
{
"id": "186dfca3-9133-4db8-9b27-d3203dd2e80a",
"type": "number",
"label": "years_of_experience",
"parentId": "d407e894-d8e7-419d-8462-5bf361e3083d",
"validation": {
"format": "integer",
"required": true,
"min": 0,
"max": 50
},
"presentation": {
"form": {
"type": "input",
"label": "Years of Experience",
"placeholder": "0",
"helpText": "Enter a value between 0 and 50"
}
}
},
{
"id": "030d8c25-9133-4ab7-9dfe-f00cce153565",
"type": "dropdown",
"label": "department",
"parentId": "d407e894-d8e7-419d-8462-5bf361e3083d",
"validation": {
"required": true,
"options": [
{
"id": "a3fa97d3-13e8-4ed0-8f72-7f8f341a337a",
"label": "Engineering",
"value": "engineering"
},
{
"id": "f25aa7a2-658f-4b60-8f31-bbcf902115cd",
"label": "Design",
"value": "design"
},
{
"id": "c7d8e9f0-1234-5678-9abc-def012345678",
"label": "Product",
"value": "product"
}
]
},
"presentation": {
"form": {
"type": "select",
"label": "Department",
"placeholder": "Select a department"
}
}
},
{
"id": "da800b8e-afae-4191-a05b-c7041ff6b07d",
"type": "radio",
"label": "work_arrangement",
"parentId": "d407e894-d8e7-419d-8462-5bf361e3083d",
"validation": {
"required": true,
"options": [
{
"id": "4770aed0-a624-49ad-9cf3-c46066c1d955",
"label": "Remote",
"value": "remote"
},
{
"id": "eb316d5d-11a5-4630-a401-a9807067a210",
"label": "Hybrid",
"value": "hybrid"
},
{
"id": "f1a2b3c4-5678-9012-3456-789012345678",
"label": "On-site",
"value": "onsite"
}
]
},
"presentation": {
"form": {
"type": "radio",
"label": "Work Arrangement"
}
}
},
{
"id": "4cc8bfb0-a8f2-475c-b272-017b9ab9eb9f",
"type": "list",
"label": "benefits",
"parentId": "d407e894-d8e7-419d-8462-5bf361e3083d",
"hidden": true,
"validation": {
"required": false,
"options": [
{
"id": "3035ee2a-5f84-444d-b52e-a4524dda17c6",
"label": "Health insurance",
"value": "health"
},
{
"id": "b9c1a72f-6de3-4e88-bf91-2f3d84c1e5a7",
"label": "401(k) matching",
"value": "retirement"
},
{
"id": "d7e4f190-3bc8-4a5d-9e12-8c6a2b4f7d01",
"label": "Professional development",
"value": "learning"
}
]
},
"presentation": {
"form": {
"type": "checkbox",
"label": "Benefits of Interest",
"allowCheckAll": false
}
}
},
{
"id": "6d45f473-4489-4f43-aa2f-a8c4c5364daa",
"type": "date",
"label": "start_date",
"parentId": "d407e894-d8e7-419d-8462-5bf361e3083d",
"validation": {
"required": true,
"dateTimeConfig": {
"dateRange": {
"start": "2026-04-01T00:00:00.000Z"
}
}
},
"presentation": {
"form": {
"label": "Earliest Start Date",
"placeholder": "MM/dd/yyyy",
"dateTimeConfig": {
"dateFormat": "MM/dd/yyyy",
"displayView": "calendar"
}
}
}
},
{
"id": "08c11aff-7ce7-43dd-94bc-79b1f9a5073a",
"type": "time",
"label": "interview_time",
"parentId": "d407e894-d8e7-419d-8462-5bf361e3083d",
"validation": {
"required": false
},
"presentation": {
"form": {
"label": "Preferred Interview Time",
"placeholder": "h:mm a",
"dateTimeConfig": {
"timeFormat": "h:mm a",
"displayView": "time_picker",
"timeIncrement": 30
}
}
}
},
{
"id": "6e2791cd-c790-4116-874c-7770bcd40a8b",
"type": "datetime",
"label": "follow_up",
"parentId": "d407e894-d8e7-419d-8462-5bf361e3083d",
"validation": {
"required": false,
"dateTimeConfig": {
"dateRange": {
"start": "2026-03-23T00:00:00.000Z"
}
}
},
"presentation": {
"form": {
"label": "Preferred Follow-up Date & Time",
"placeholder": "MM/dd/yyyy h:mm a",
"dateTimeConfig": {
"dateFormat": "MM/dd/yyyy",
"timeFormat": "h:mm a",
"displayView": "calendar",
"timeIncrement": 15
}
}
}
},
{
"id": "08bcc923-cbab-4f3c-b491-bf5693f29f1a",
"type": "static_content",
"label": "terms",
"parentId": "d407e894-d8e7-419d-8462-5bf361e3083d",
"presentation": {
"form": {
"type": "html",
"label": "Terms & Conditions",
"content": "<p>By submitting this application you agree to our privacy policy.</p>"
}
}
}
]
}
],
"logic": {
"logicRules": [
{
"id": "d96235f7-96a8-44f1-86f0-e2fb9eccd6ff",
"name": "Require phone for on-site",
"actions": [
{
"id": "75867a52-5e69-4b7b-ba28-1ae5d2dfcab6",
"type": "component_action",
"componentAction": {
"type": "make_required",
"componentId": "53839acd-f783-43a0-9212-d33e8d926e45"
}
}
],
"condition": {
"id": "3dde07d0-1aa6-4897-9a10-9f84f6989d1f",
"mode": "and",
"conditions": [
{
"id": "838f5cac-4c21-4a32-8ff2-3c4d0fe85132",
"mode": "and",
"name": "Conditions group",
"conditions": [
{
"id": "66b681db-df2e-4afa-a2ad-455d7c8a5315",
"rule": {
"id": "36ba5755-a57a-4acc-9bcf-881707a2ca06",
"type": "string_comparison",
"operator": "is",
"leftHandExpression": {
"type": "field_template",
"value": "{{`Job Application`.`findComponentValueById.da800b8e-afae-4191-a05b-c7041ff6b07d`}}",
"dataMappingType": "radio"
},
"rightHandExpression": {
"type": "literal_template",
"value": "{{`Job Application`.`findOptionById.f1a2b3c4-5678-9012-3456-789012345678`}}",
"dataMappingType": "text"
}
}
}
]
}
]
}
},
{
"id": "c515d935-3f81-4214-8b75-cdbd0348739d",
"name": "Show benefits for Engineering",
"actions": [
{
"id": "665f1a94-327a-444e-83b5-ba15f01cec2d",
"type": "component_action",
"componentAction": {
"type": "show",
"componentId": "4cc8bfb0-a8f2-475c-b272-017b9ab9eb9f"
}
}
],
"condition": {
"id": "04bc4091-20a8-4e6d-ac91-037f8c215855",
"mode": "and",
"conditions": [
{
"id": "305acd16-3e58-4645-baf4-00c398304a6f",
"mode": "and",
"name": "Conditions group",
"conditions": [
{
"id": "cc084e22-907a-4dbc-9e55-3c8cdedcec1c",
"rule": {
"id": "70f3d21b-3292-4c7b-881d-dd4f8c689b96",
"type": "string_comparison",
"operator": "is",
"leftHandExpression": {
"type": "field_template",
"value": "{{`Job Application`.`findComponentValueById.030d8c25-9133-4ab7-9dfe-f00cce153565`}}",
"dataMappingType": "dropdown"
},
"rightHandExpression": {
"type": "literal_template",
"value": "{{`Job Application`.`findOptionById.a3fa97d3-13e8-4ed0-8f72-7f8f341a337a`}}",
"dataMappingType": "text"
}
}
}
]
}
]
}
},
{
"id": "a5261dc4-e2c8-45e4-9c9f-a893dcb20ab2",
"name": "Block submission with no experience",
"actions": [
{
"id": "b6299c6c-bc9b-4643-b0ae-2225444e8928",
"type": "disable_submission"
}
],
"condition": {
"id": "c4a77f9a-13da-4512-ad8a-b3b26c78dd7f",
"mode": "and",
"conditions": [
{
"id": "16fc3b58-9ec3-4efd-8581-af2e0afd0f37",
"mode": "and",
"name": "Conditions group",
"conditions": [
{
"id": "47581234-c67b-4940-803e-2156d9cdabaf",
"rule": {
"id": "9dbc036a-6e22-4aa8-9a7c-fd5272f3e60c",
"type": "number_comparison",
"operator": "is_less_than_or_equal_to",
"leftHandExpression": {
"type": "field_template",
"value": "{{`Job Application`.`findComponentValueById.186dfca3-9133-4db8-9b27-d3203dd2e80a`}}",
"dataMappingType": "number"
},
"rightHandExpression": {
"type": "arithmetic_template",
"value": "0",
"dataMappingType": "text"
}
}
}
]
}
]
}
}
]
}
}Updated 1 day ago
