Node Configuration
Nodes are the building blocks of workflows. Each node type has specific properties and behaviors.
Node Properties
All nodes share common properties:
Basic Properties
- Code (required) – Unique identifier within workflow
- Name (required) – Display name
- Label – Short label for UI
- Description – Detailed description
Position
- X, Y – Canvas coordinates (automatically set when dragging)
Data Properties
- UI – UI configuration object
- Exec – Execution configuration object
- Actions – Array of action buttons
- Input Handle – Input connection point
- Output Handles – Output connection points
State Node
State nodes represent steps in the workflow that require user interaction.
UI Configuration
{
type: "MODEL_FORM" | "CUSTOM_FORM" | "OTP_FORM" | "PASSWORD_FORM" | "PIN_FORM" | "DISCLAIMER_PAGE" | "END_PAGE",
formClass?: string, // For CUSTOM_FORM
model?: string, // For MODEL_FORM
title?: string,
subtitle?: string,
fields?: FieldConfig[], // For MODEL_FORM
}
Run Type
- "0" – UI mode (requires user interaction)
- "1" – Exec mode (runs automatically)
Actions
Array of action buttons:
{
id: string,
code?: string,
name?: string,
label: string,
type: "NEXT" | "SKIP" | "SUBMIT" | "VERIFY" | "FUNCTION",
handle?: string, // Output handle to follow
url?: string, // API endpoint for SUBMIT
}
Example Configuration
{
code: "personal-data",
name: "Personal Data",
label: "Personal Info",
description: "Enter your personal information",
ui: {
type: "MODEL_FORM",
model: "Person",
title: "Personal Information",
subtitle: "Please fill in your details",
},
runType: "0",
actions: [
{
id: "next",
label: "Next",
type: "NEXT",
handle: "0",
},
],
}
Decision Node
Decision nodes branch workflows based on conditions.
Conditions
Array of conditions to evaluate:
{
field: string, // Field path in workflow values
operator: "equals" | "notEquals" | "greaterThan" | "lessThan" | "greaterThanOrEqual" | "lessThanOrEqual",
value: any, // Value to compare against
}
Output Handles
Each handle represents a condition outcome:
- Handle "0" – First condition true
- Handle "1" – Second condition true
- Handle "default" – No conditions match
Example Configuration
{
code: "check-age",
name: "Check Age",
description: "Verify user is 18 or older",
conditions: [
{
field: "person.age",
operator: "greaterThanOrEqual",
value: 18,
},
],
outputHandles: [
{ id: "0", label: "Adult" },
{ id: "1", label: "Minor" },
],
}
Start Node
Entry point of workflow. Must have exactly one output handle.
Configuration
{
code: "start",
name: "Start",
description: "Workflow entry point",
}
End Node
Exit point of workflow.
Configuration
{
code: "end",
name: "End",
description: "Workflow completion",
ui: {
type: "END_PAGE",
title: "Complete",
message: "Thank you for completing the workflow",
},
}
UI Types
MODEL_FORM
Auto-generated form from model definition:
{
type: "MODEL_FORM",
model: "Person", // Model name from @xond/api
title: "Personal Information",
subtitle: "Enter your details",
fields: [
// Optional: override field configuration
{
fieldName: "name",
label: "Full Name",
fieldWidth: "wide",
},
],
}
CUSTOM_FORM
Custom React component:
{
type: "CUSTOM_FORM",
formClass: "PersonalDataForm", // Must be registered in FormRegistryContext
title: "Custom Form",
subtitle: "Custom form description",
}
OTP_FORM
One-time password input:
{
type: "OTP_FORM",
title: "Verify OTP",
subtitle: "Enter the code sent to your phone",
length: 6, // OTP length
fieldName: "otpCode", // Field name in workflow values
}
PASSWORD_FORM
Password input:
{
type: "PASSWORD_FORM",
title: "Set Password",
subtitle: "Choose a secure password",
fieldName: "password",
confirmFieldName: "confirmPassword",
}
PIN_FORM
PIN code input:
{
type: "PIN_FORM",
title: "Set PIN",
subtitle: "Enter a 6-digit PIN",
length: 6,
fieldName: "pin",
}
DISCLAIMER_PAGE
Terms and conditions page:
{
type: "DISCLAIMER_PAGE",
title: "Terms and Conditions",
content: "By proceeding, you agree to...",
checkboxLabel: "I agree to the terms",
fieldName: "agreed",
}
END_PAGE
Completion page:
{
type: "END_PAGE",
title: "Complete",
message: "Thank you for completing the workflow",
showActions: false, // Hide action buttons
}
Action Types
NEXT
Proceed to next node:
{
type: "NEXT",
label: "Next",
handle: "0", // Output handle to follow
}
SKIP
Skip to specified handle:
{
type: "SKIP",
label: "Skip",
handle: "1", // Output handle to skip to
}
SUBMIT
Submit data to API endpoint:
{
type: "SUBMIT",
label: "Submit",
url: "/api/submit",
handle: "0", // Output handle on success
}
VERIFY
Verify data (e.g., OTP):
{
type: "VERIFY",
label: "Verify",
url: "/api/verify-otp",
handle: "0", // Output handle on success
errorHandle: "1", // Output handle on failure
}
FUNCTION
Execute custom function:
{
type: "FUNCTION",
label: "Custom Action",
functionName: "customFunction",
handle: "0",
}
Workflow Values
Nodes can access values from previous nodes:
// Access values in conditions
{
field: "person.name", // Access person.name from workflow values
operator: "equals",
value: "John",
}
// Values are merged from all previous nodes
// Use copyToRoot: true to make values available to all subsequent nodes
Best Practices
- Use meaningful codes – Make node codes descriptive
- Add descriptions – Help users understand each step
- Configure UI properly – Set titles and subtitles for better UX
- Handle errors – Add error handles for SUBMIT and VERIFY actions
- Test conditions – Verify decision node conditions work correctly
- Use MODEL_FORM when possible – Leverage auto-generated forms
- Register custom forms – Add custom forms to FormRegistryContext
Next Steps
- Learn about workflow execution
- Create custom forms
- Explore integration patterns