Application Experiences: UDL Forms Guide
Overview
UDL (User-Defined Layout) forms provide a flexible, JSON-based system for creating dynamic forms within Application Experiences. These forms seamlessly integrate with workflows, enabling powerful data collection and processing capabilities.
Key Features
- JSON-based Configuration: Define forms using a simple, readable JSON schema
- Workflow Integration: Connect forms directly to workflows for automated processing
- Component Library: Rich set of input types and layout options
- Real-time Data Flow: Automatic synchronization between forms, workflows, and workspaces
- Multi-step Support: Create wizard-style forms for complex data collection
Quick Start
Creating Your First Form
- Navigate to the organization-scoped Application Experiences page
- Create a new Application Experience or select an existing one
- Edit the JSON configuration to define your form structure
Basic Form Example
{
"name": "Contact Form",
"url": "contact-form",
"children": [
{
"type": "form",
"title": "Get in Touch",
"workflowId": "contact-workflow-id",
"children": [
{
"type": "text",
"label": "Your Name",
"parameter": "name",
"required": true
},
{
"type": "text",
"label": "Email",
"parameter": "email",
"pattern": "^[\\w-\\.]+@([\\w-]+\\.)+[\\w-]{2,4}$"
},
{
"type": "text",
"label": "Message",
"parameter": "message",
"multiline": true
},
{
"type": "button",
"label": "Submit",
"action": "submit"
}
]
}
]
}
How Forms Work
Form Execution Flow
When users interact with forms through the Application Experience execution page (accessible via the Public Demo page):
- Form Rendering: The JSON configuration is parsed and rendered as an interactive form
- Data Collection: User inputs are collected and validated in real-time
- Workflow Execution: On submission, data is passed to connected workflows. If the submit button (within the workflow's form children) has
updateParameters: true, the data becomes available to other workflows; otherwise, it is only available to itself - Result Processing: Workflow outputs are merged back into the workspace
Data Management
External Workspace
The system maintains an external workspace that:
- Stores form data and workflow results
- Provides access to UDL forms sub-workflows
- Automatically propagates changes to all connected components
Parameter Handling
- Form to Workflow: Field values are mapped to WorkflowParameters of the connected workflow using their
parameternames. If a parameter name doesn't match any WorkflowParameter, the input value will not be passed to the workflow - Global Parameters: A global object stores values when
updateParameters: trueis set on buttons - Parameter Conflicts: Variables are scoped to forms. When multiple fields within a form share the same parameter name, the last value overwrites previous ones. If a button within the form has
updateParameters: true, it will overwrite the global parameters - Workflow Results: Outputs from workflow runs are merged back into the external workspace
Form Schema Reference
Top-Level Structure
| Field | Type | Required | Description |
|---|---|---|---|
$schema |
string |
No | Optional schema version identifier |
name |
string |
Yes | Display name of the form |
url |
string |
Yes | Unique URL slug for the form |
children |
Component[] |
Yes | Array of form components |
Base Component Properties
All components share these common properties:
| Field | Type | Required | Description |
|---|---|---|---|
type |
string |
Yes | Component type identifier |
Field-Specific Properties
Input fields share these additional properties:
| Field | Type | Required | Description |
|---|---|---|---|
label |
string |
Yes | Display label for the field |
parameter |
string or object[] |
Yes | Unique identifier or array of parameter objects |
required |
boolean |
No | Mark field as required (default: false) |
hidden |
boolean |
No | Hide field from UI (default: false) |
defaultValue |
any |
No | Default value before user interaction |
Component Types
Container Components
Form Container
The top-level container for form fields.
{
"type": "form",
"title": "Registration Form",
"workflowId": "workflow-123",
"workflowVersionId": "v1",
"children": [...]
}
| Field | Type | Required | Description |
|---|---|---|---|
title |
string |
No | Form title |
workflowId |
string |
No | Connected workflow ID |
workflowVersionId |
string |
No | Specific workflow version |
children |
Component[] |
Yes | Form components |
Fieldset
Groups related fields visually and semantically.
{
"type": "fieldset",
"legend": "Personal Information",
"children": [...]
}
| Field | Type | Required | Description |
|---|---|---|---|
legend |
string |
No | Group label |
children |
Component[] |
Yes | Grouped components |
Wizard
Creates multi-step forms for complex workflows.
{
"type": "wizard",
"steps": [
{
"type": "wizardstep",
"title": "Step 1",
"children": [...]
}
]
}
Input Components
Text Input
Single or multi-line text input.
{
"type": "text",
"label": "Description",
"parameter": "description",
"multiline": true,
"pattern": "^[a-zA-Z0-9\\s]+$",
"defaultValue": "Enter description here"
}
| Field | Type | Required | Description |
|---|---|---|---|
parameter |
string |
Yes | Should match a WorkflowParameter name in the connected workflow |
multiline |
boolean |
No | Enable multi-line input |
pattern |
string |
No | Validation regex pattern |
defaultValue |
string |
No | Pre-filled value |
Number Input
Numeric input with optional constraints.
{
"type": "number",
"label": "Age",
"parameter": "age",
"min": 18,
"max": 100,
"defaultValue": 25
}
| Field | Type | Required | Description |
|---|---|---|---|
parameter |
string |
Yes | Should match a WorkflowParameter name in the connected workflow |
min |
number |
No | Minimum value |
max |
number |
No | Maximum value |
defaultValue |
number |
No | Default value |
Dropdown List
Single selection from predefined options or workspace files/folders.
{
"type": "dropdownlist",
"label": "Country",
"parameter": "country",
"options": ["USA", "Canada", "UK", "Australia"],
"defaultValue": "USA"
}
Workspace File Selection For dynamic file/folder selection from workspace:
{
"type": "dropdownlist",
"label": "Select Configuration File",
"parameter": "config_file",
"globPattern": "config/*.json",
"globType": "files",
"displayMode": "relative"
}
Workspace Folder Selection For selecting folders from workspace:
{
"type": "dropdownlist",
"label": "Select Project Folder",
"parameter": "project_folder",
"globPattern": "projects/*",
"globType": "folders",
"displayMode": "relative"
}
| Field | Type | Required | Description |
|---|---|---|---|
parameter |
string |
Yes | Should match a WorkflowParameter name in the connected workflow |
options |
string[] |
No | Static dropdown options |
defaultValue |
string |
No | Default selected option |
globPattern |
string |
No | Glob pattern for workspace file/folder selection |
globType |
"files", "folders", or "all" |
No | Type of workspace items to include (default: "files") |
displayMode |
"relative" or "fullpath" |
No | How to display paths (default: "fullpath") |
Checkbox
Single boolean input.
{
"type": "checkbox",
"label": "I agree to terms",
"parameter": "terms_agreed",
"defaultValue": false
}
Checkbox List
Multiple selections from options.
{
"type": "checkboxlist",
"label": "Interests",
"parameter": "interests",
"options": ["Sports", "Music", "Technology", "Travel"],
"defaultValue": ["Technology"]
}
Radio Button List
Exclusive selection from options.
{
"type": "radiobuttonlist",
"label": "Preferred Contact",
"parameter": "contact_method",
"options": ["Email", "Phone", "SMS"],
"defaultValue": "Email"
}
Matrix Selection
Grid-based selection for rating or evaluation forms.
{
"type": "matrixselection",
"label": "Service Rating",
"parameter": [
{"id": "quality", "label": "Quality of Service"},
{"id": "speed", "label": "Response Speed"},
{"id": "support", "label": "Customer Support"}
],
"scales": [
{"label": "Poor", "value": "1"},
{"label": "Fair", "value": "2"},
{"label": "Good", "value": "3"},
{"label": "Excellent", "value": "4"}
],
"defaultValue": [
{"parameter": "quality", "value": "3"},
{"parameter": "speed", "value": "3"}
]
}
| Field | Type | Required | Description |
|---|---|---|---|
parameter |
{id: string, label: string}[] |
Yes | Array of parameter objects for matrix rows |
scales |
{label: string, value?: string}[] |
Yes | Available matrix selection options |
defaultValue |
{parameter: string, value: string}[] |
No | Default selected values |
Action Components
Button
Triggers form actions or navigation.
{
"type": "button",
"label": "Continue",
"action": "next",
"variant": "contained",
"advance": 1,
"updateParameters": true
}
| Field | Type | Required | Description |
|---|---|---|---|
action |
"submit" or "next" |
Yes | Button behavior |
variant |
"outlined" or "contained" |
No | Visual style |
advance |
number |
No | Steps to advance in wizard |
updateParameters |
boolean |
No | Update global parameters |
Layout Components
Stack
Flexible container for arranging components.
{
"type": "stack",
"direction": "horizontal",
"gap": 16,
"justify": "space-between",
"align": "center",
"wrap": true,
"reverse": false,
"children": [...]
}
| Field | Type | Required | Description |
|---|---|---|---|
direction |
"horizontal" or "vertical" |
No | Layout direction (default: vertical) |
gap |
number |
No | Spacing between child elements |
justify |
"start", "center", "end", "space-between", "space-around", or "space-evenly" |
No | Main-axis alignment |
align |
"start", "center", "end", "stretch", or "baseline" |
No | Cross-axis alignment |
wrap |
boolean |
No | Allow wrapping to next line |
reverse |
boolean |
No | Reverse the order of children |
children |
Component[] |
Yes | Nested components |
Complete Example
Here's a comprehensive example demonstrating various features:
{
"$schema": "https://example.com/schemas/udl-form-v1.json",
"name": "Employee Onboarding Form",
"url": "employee-onboarding",
"children": [
{
"type": "form",
"title": "New Employee Information",
"workflowId": "onboarding-workflow",
"children": [
{
"type": "wizard",
"steps": [
{
"type": "wizardstep",
"title": "Personal Details",
"children": [
{
"type": "fieldset",
"legend": "Basic Information",
"children": [
{
"type": "text",
"label": "Full Name",
"parameter": "full_name",
"required": true
},
{
"type": "text",
"label": "Email",
"parameter": "email",
"pattern": "^[\\w-\\.]+@company\\.com$"
},
{
"type": "number",
"label": "Employee ID",
"parameter": "employee_id",
"min": 1000,
"max": 99999
}
]
}
]
},
{
"type": "wizardstep",
"title": "Department & Role",
"children": [
{
"type": "dropdownlist",
"label": "Department",
"parameter": "department",
"options": ["Engineering", "Sales", "Marketing", "HR", "Finance"]
},
{
"type": "radiobuttonlist",
"label": "Employment Type",
"parameter": "employment_type",
"options": ["Full-time", "Part-time", "Contract"],
"defaultValue": "Full-time"
}
]
},
{
"type": "wizardstep",
"title": "Equipment & Access",
"children": [
{
"type": "checkboxlist",
"label": "Required Equipment",
"parameter": "equipment",
"options": ["Laptop", "Monitor", "Keyboard", "Mouse", "Headset"],
"defaultValue": ["Laptop"]
},
{
"type": "checkbox",
"label": "Remote Access Required",
"parameter": "remote_access",
"defaultValue": true
},
{
"type": "matrixselection",
"label": "Rate Your Priorities",
"parameter": [
{"id": "work_life_balance", "label": "Work-Life Balance"},
{"id": "career_growth", "label": "Career Growth"},
{"id": "compensation", "label": "Compensation"}
],
"scales": [
{"label": "Low", "value": "1"},
{"label": "Medium", "value": "2"},
{"label": "High", "value": "3"},
{"label": "Critical", "value": "4"}
]
}
]
}
]
},
{
"type": "stack",
"direction": "horizontal",
"gap": 12,
"justify": "end",
"children": [
{
"type": "button",
"label": "Previous",
"action": "next",
"advance": -1,
"variant": "outlined"
},
{
"type": "button",
"label": "Next",
"action": "next",
"advance": 1,
"variant": "contained"
},
{
"type": "button",
"label": "Submit",
"action": "submit",
"variant": "contained",
"updateParameters": true
}
]
}
]
}
]
}
Best Practices
Form Design
- Group Related Fields: Use fieldsets to organize related inputs
- Progressive Disclosure: Use wizards for complex forms to avoid overwhelming users
- Clear Labels: Provide descriptive, concise labels for all fields
- Smart Defaults: Set sensible default values to speed up form completion
Parameter Naming
- Match Workflow Parameters: Parameter names should exactly match the WorkflowParameter names defined in your connected workflow. Unmatched parameters will not be passed to the workflow
- Avoid Conflicts: Ensure parameter names are unique unless intentionally sharing data
Validation
- Client-Side Patterns: Use regex patterns for immediate validation feedback
- Required Fields: Mark essential fields as required
- Constraints: Set appropriate min/max values for numeric inputs
Workflow Integration
- Plan Data Flow: Map out how form parameters align with WorkflowParameters in your workflows
- Testing: Test the complete flow from form submission to workflow completion
Troubleshooting
Common Issues
Form Not Rendering - Verify JSON syntax is valid - Check that all required fields are present - Ensure component types are spelled correctly (case-sensitive)
Data Not Passing to Workflow
- Confirm form parameter names exactly match WorkflowParameter names in your workflow (mismatched names will be silently ignored)
- Check that the workflow ID and version are correct
- Verify updateParameters is set to true on submit buttons
- Ensure WorkflowParameters are properly defined in the workflow builder
- Note: The form will not error if parameter names don't match - the values simply won't be passed
Validation Not Working - Test regex patterns separately - Ensure patterns are properly escaped in JSON - Check that the pattern matches the expected input format
Technical Notes
- Component
typefields are case-sensitive - All input components require a
parameterfield - Parameters with names that don't match WorkflowParameter names will be silently ignored - no error will be shown
- The schema is validated using Zod
- Form state is maintained in the external workspace throughout the session
- Workflow outputs automatically update the UI when merged into the workspace