Skip to main content

Advanced Features & Patterns

Deep dive into advanced Page Designer features including workflow configuration, calculated fields, complex data binding, and production patterns.

Workflow Configuration

Workflow Triggers

Workflows are triggered by field changes, form submission, or scheduled events.

export interface WorkflowConfig {
id: string;
name: string;
trigger:
| "onChange"
| "onSubmit"
| "onFocus"
| "onBlur"
| "schedule"
| "manual";

// Conditional execution
conditions?: ConditionalLogic;

// Actions
actions: WorkflowAction[];

// Execution settings
async?: boolean; // Non-blocking
retryCount?: number;
timeout?: number; // ms
stopOnError?: boolean;

// Notifications
showNotification?: boolean;
notificationMessage?: string;
}

Workflow Actions

Email Action

Send email notifications

{
"type": "email",
"to": "user@example.com",
"toField": "emailField",
"cc": ["admin@example.com"],
"subject": "Form Submission: {form_name}",
"template": "form_submitted",
"variables": {
"userName": "{firstName}",
"orderAmount": "{total}",
"timestamp": "{{now}}"
}
}

Data Update Action

Update records in the system

{
"type": "dataUpdate",
"entity": "users",
"operation": "insert|update|delete",
"condition": {
"when": "status",
"operator": "equals",
"value": "premium"
},
"mappings": {
"name": "{firstName} {lastName}",
"email": "{email}",
"phone": "{phone}",
"preferences": {
"newsletter": "{subscribeNewsletter}",
"notifications": "{enableNotifications}"
}
}
}

API Call Action

Invoke external APIs

{
"type": "apiCall",
"method": "POST|GET|PUT|DELETE|PATCH",
"url": "https://api.example.com/submit",
"headers": {
"Authorization": "Bearer {authToken}",
"Content-Type": "application/json"
},
"payload": {
"orderId": "{orderNumber}",
"amount": "{total}",
"currency": "USD"
},
"responseMapping": {
"confirmationId": {
"path": "data.transactionId",
"targetField": "transactionId"
},
"status": {
"path": "data.status",
"targetField": "orderStatus"
}
}
}

Webhook Action

Trigger external webhooks

{
"type": "webhook",
"url": "https://webhook.example.com/forms",
"authentication": "bearer_token|api_key|basic",
"token": "{webhookToken}",
"payload": {
"event": "form_submitted",
"formId": "{form_id}",
"data": "{formData}",
"metadata": {
"timestamp": "{{now}}",
"userId": "{currentUserId}"
}
}
}

File Upload Action

Process uploaded files

{
"type": "fileUpload",
"targetField": "documentFile",
"destination": "s3|azure|local",
"bucket": "form-uploads",
"prefix": "documents/{year}/{month}/",
"encryption": true,
"maxSize": 10485760,
"allowedTypes": ["pdf", "doc", "docx"]
}

Conditional Branch Action

Execute different actions based on conditions

{
"type": "branch",
"conditions": [
{
"when": "amount",
"operator": "greaterThan",
"value": 10000,
"thenActions": [
{
"type": "email",
"to": "compliance@example.com",
"subject": "Large transaction approval required"
}
]
}
],
"elseActions": [
{
"type": "email",
"to": "user@example.com",
"subject": "Transaction approved"
}
]
}

Notification Action

Display in-app notifications

{
"type": "notification",
"style": "success|info|warning|error",
"title": "Success!",
"message": "Your application has been submitted",
"duration": 5000,
"action": {
"label": "View Status",
"url": "/applications/{applicationId}"
}
}

Workflow Example: Multi-Step Approval

{
"id": "expense_approval",
"name": "Expense Approval Workflow",
"trigger": "onSubmit",
"actions": [
{
"type": "dataUpdate",
"entity": "expenses",
"operation": "insert",
"mappings": {
"amount": "{expenseAmount}",
"category": "{category}",
"description": "{description}",
"submittedBy": "{currentUserId}",
"status": "pending"
}
},
{
"type": "branch",
"conditions": [
{
"when": "expenseAmount",
"operator": "greaterThan",
"value": 5000,
"thenActions": [
{
"type": "email",
"to": "director@example.com",
"subject": "Large expense approval required: ${expenseAmount}",
"template": "large_expense_approval"
}
]
}
],
"elseActions": [
{
"type": "email",
"to": "manager@example.com",
"subject": "Expense submitted: ${expenseAmount}",
"template": "standard_expense_notification"
}
]
},
{
"type": "notification",
"style": "success",
"message": "Your expense has been submitted for approval"
}
]
}

Calculated Fields

Formula-Based Calculation

Use mathematical expressions for numeric calculations:

export interface CalculatedValue {
type: "formula" | "javascript" | "transform" | "aggregate";
trigger: "onChange" | "onLoad" | "onSave";

// Formula-specific
formula?: string;
rounding?: number;

// JavaScript-specific
code?: string;
dependencies?: string[]; // Watched field IDs

// Transform-specific
transformType?: "uppercase" | "lowercase" | "capitalize" | "trim" | "reverse";

// Aggregate-specific
aggregationType?: "sum" | "avg" | "count" | "min" | "max";
sourceField?: string; // Field ID to aggregate
}

Formula Examples

[
{
"type": "formula",
"name": "Tax Calculation",
"formula": "subtotal * taxRate / 100",
"rounding": 2
},
{
"type": "formula",
"name": "Total Amount",
"formula": "subtotal + tax + shipping - discount",
"rounding": 2
},
{
"type": "formula",
"name": "Percentage Complete",
"formula": "(completedTasks / totalTasks) * 100",
"rounding": 1
},
{
"type": "formula",
"name": "Compound Interest",
"formula": "principal * (1 + rate/100)^years",
"rounding": 2
}
]

JavaScript Calculations

Complex logic using JavaScript:

{
"type": "javascript",
"code": `
const today = new Date();
const birthDate = new Date(fields.dateOfBirth);
const age = today.getFullYear() - birthDate.getFullYear();
const monthDiff = today.getMonth() - birthDate.getMonth();

if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDate.getDate())) {
return age - 1;
}

return age;
`,
"dependencies": ["dateOfBirth"]
}

Aggregate Calculations

Sum, average, or count across field collections:

{
"type": "aggregate",
"aggregationType": "sum",
"sourceField": "lineItems",
"operation": "items.reduce((sum, item) => sum + item.quantity * item.price, 0)"
}

Transform Functions

String manipulation and formatting:

[
{
"type": "transform",
"transformType": "uppercase",
"sourceName": "productName",
"targetName": "displayName"
},
{
"type": "formula",
"formula": "firstName + ' ' + lastName",
"targetName": "fullName"
},
{
"type": "javascript",
"code": "phone.replace(/^(\\d{3})(\\d{3})(\\d{4})$/, '($1) $2-$3')",
"targetName": "formattedPhone"
}
]

Advanced Data Binding

Two-Way Binding

Synchronize form state with external data source:

export interface DataBinding {
type: "oneWay" | "twoWay";
sourceField: string; // External data path
targetField: string; // Form field ID
transformer?: (value: any) => any; // Transform on read
reverseTransformer?: (value: any) => any; // Transform on write
debounce?: number; // ms
}

Example: Real-Time Product Details

{
"fields": [
{
"id": "productCode",
"type": "autocomplete",
"label": "Product Code",
"dataSource": {
"type": "api",
"url": "/api/products/search?q={query}"
}
},
{
"id": "productName",
"type": "text",
"label": "Product Name",
"readOnly": true,
"dataBinding": {
"type": "twoWay",
"sourceField": "selectedProduct.name"
}
},
{
"id": "unitPrice",
"type": "currency",
"label": "Unit Price",
"readOnly": true,
"dataBinding": {
"type": "twoWay",
"sourceField": "selectedProduct.price"
}
},
{
"id": "quantity",
"type": "number",
"label": "Quantity"
},
{
"id": "totalAmount",
"type": "currency",
"label": "Total",
"readOnly": true,
"calculated": {
"type": "javascript",
"code": "return parseFloat(unitPrice || 0) * parseFloat(quantity || 0);",
"dependencies": ["unitPrice", "quantity"]
}
}
]
}

Master-Detail Pattern

Parent-child form relationships:

{
"id": "order_form",
"fields": [
{
"id": "orderId",
"type": "text",
"label": "Order ID",
"readOnly": true
},
{
"id": "customerName",
"type": "autocomplete",
"label": "Customer",
"dataSource": {
"type": "api",
"url": "/api/customers"
}
},
{
"id": "orderItems",
"type": "repeater",
"label": "Order Items",
"children": [
{
"id": "product",
"type": "autocomplete",
"label": "Product",
"dataSource": {
"type": "api",
"url": "/api/products",
"params": {
"category": "{parentScope.category}"
}
}
},
{
"id": "quantity",
"type": "number",
"label": "Quantity"
},
{
"id": "price",
"type": "currency",
"label": "Unit Price",
"readOnly": true,
"dataBinding": {
"sourceField": "product.price"
}
},
{
"id": "lineTotal",
"type": "currency",
"label": "Total",
"readOnly": true,
"calculated": {
"formula": "quantity * price"
}
}
]
},
{
"id": "grandTotal",
"type": "currency",
"label": "Grand Total",
"readOnly": true,
"calculated": {
"type": "javascript",
"code": "return orderItems.reduce((sum, item) => sum + (item.lineTotal || 0), 0);",
"dependencies": ["orderItems"]
}
}
]
}

Cascading Dropdowns

Chain dropdown selections based on parent values:

{
"fields": [
{
"id": "country",
"type": "select",
"label": "Country",
"dataSource": {
"type": "api",
"url": "/api/countries"
}
},
{
"id": "state",
"type": "select",
"label": "State",
"dataSource": {
"type": "api",
"url": "/api/states",
"params": {
"countryId": "{country}"
}
},
"conditional": {
"rules": [
{
"when": "country",
"operator": "isNotEmpty",
"action": "show"
}
]
}
},
{
"id": "city",
"type": "select",
"label": "City",
"dataSource": {
"type": "api",
"url": "/api/cities",
"params": {
"stateId": "{state}"
}
},
"conditional": {
"rules": [
{
"when": "state",
"operator": "isNotEmpty",
"action": "show"
}
]
}
}
]
}

Dynamic Form Generation

Programmatically create forms based on data:

export const generateFormFromData = (data: any): FormSchema => {
const fields = Object.entries(data).map(([key, value]) => {
const fieldType = inferFieldType(value);

return {
id: key,
name: key,
type: fieldType,
label: humanize(key),
placeholder: `Enter ${humanize(key)}`,
required: value !== null && value !== undefined,
defaultValue: value,
};
});

return {
id: "generated-form",
name: "Generated Form",
fields,
};
};

const inferFieldType = (value: any): FieldType => {
if (typeof value === "boolean") return "switch";
if (typeof value === "number") return "number";
if (value instanceof Date) return "date";
if (Array.isArray(value)) return "repeater";
if (typeof value === "object") return "panel";
return "text";
};

Custom Validation Patterns

Cross-Field Validation

Validate one field based on another:

{
"id": "matchPassword",
"type": "password",
"label": "Confirm Password",
"validationRules": [
{
"type": "comparison",
"compareField": "password",
"operator": "equals",
"message": "Passwords do not match"
}
]
}

Custom Async Validation

{
"id": "email",
"type": "email",
"label": "Email",
"validationRules": [
{
"type": "async",
"asyncValidationUrl": "/api/email/check",
"asyncMethod": "POST",
"debounceMs": 500,
"message": "This email is already registered"
}
]
}

Complex Validation Logic

{
"id": "rentalEndDate",
"type": "date",
"label": "Rental End Date",
"validationRules": [
{
"type": "comparison",
"compareField": "rentalStartDate",
"operator": "greaterThan",
"message": "End date must be after start date"
},
{
"type": "custom",
"customValidation": "
const startDate = new Date(fields.rentalStartDate);
const endDate = new Date(value);
const maxDays = 365;
const daysDiff = Math.floor((endDate - startDate) / (1000 * 60 * 60 * 24));
if (daysDiff > maxDays) {
return 'Rental period cannot exceed ' + maxDays + ' days';
}
return true;
",
"message": "Invalid rental period"
}
]
}

Accessibility (a11y)

WCAG Compliance

{
"id": "formExample",
"name": "Accessible Form",
"fields": [
{
"id": "firstName",
"type": "text",
"label": "First Name",
"required": true,
"description": "Your legal first name as shown on official documents",
"ariaLabel": "First Name (required)",
"ariaDescribedBy": "firstName-help",
"inputAttributes": {
"autoComplete": "given-name",
"role": "textbox"
}
},
{
"id": "email",
"type": "email",
"label": "Email Address",
"required": true,
"ariaLabel": "Email Address (required)",
"inputAttributes": {
"autoComplete": "email",
"spellcheck": "false"
}
}
]
}

Keyboard Navigation

  • Tab through fields in logical order
  • Enter to submit forms
  • Space/Enter to toggle checkboxes and radio buttons
  • Escape to close dialogs

Screen Reader Support

  • All fields must have labels
  • Error messages associated with fields
  • Form validation feedback announced
  • Loading states indicated

Performance Optimization

Lazy Loading Fields

For forms with many fields, lazy load below the fold:

const LazyFieldGroup = React.lazy(() =>
import('./advanced-fields')
);

export const FormRenderer = ({ schema, data }) => {
return (
<div>
{/* Render visible fields immediately */}
{schema.fields.slice(0, 10).map(field =>
renderField(field, data)
)}

{/* Lazy load remaining fields */}
<Suspense fallback={<div>Loading...</div>}>
<LazyFieldGroup
fields={schema.fields.slice(10)}
data={data}
/>
</Suspense>
</div>
);
};

Debounced Validation

Reduce validation API calls:

const debouncedValidate = useMemo(
() =>
debounce((fieldId: string, value: any) => {
validateFieldAsync(fieldId, value);
}, 500),
[],
);

Memoized Data Sources

Cache data source results:

const dataSourceCache = new Map();

const getDataSourceData = async (dataSource: DataSource) => {
const cacheKey = JSON.stringify(dataSource);

if (dataSourceCache.has(cacheKey)) {
return dataSourceCache.get(cacheKey);
}

const data = await fetchDataSource(dataSource);
dataSourceCache.set(cacheKey, data);

return data;
};

Security Considerations

Input Sanitization

export const sanitizeInput = (input: string): string => {
return DOMPurify.sanitize(input, {
ALLOWED_TAGS: [], // No HTML tags allowed
ALLOWED_ATTR: [],
});
};

// In field renderer
const handleChange = (value: string) => {
const sanitized = sanitizeInput(value);
onChange(sanitized);
};

CSRF Protection

Include CSRF tokens in API calls:

const createApiCall = (action: WorkflowAction) => {
return {
...action,
headers: {
...action.headers,
"X-CSRF-Token": getCsrfToken(),
},
};
};

XSS Prevention

Never use innerHTML directly:

// ❌ WRONG
<div dangerouslySetInnerHTML={{ __html: field.description }} />

// ✅ CORRECT
<div>{field.description}</div>

// If HTML is required, use DOMPurify
<div dangerouslySetInnerHTML={{
__html: DOMPurify.sanitize(field.description)
}} />

Monitoring & Debugging

Form Submission Tracking

const trackFormSubmission = (formId: string, data: any) => {
analytics.track("form_submitted", {
formId,
fieldCount: Object.keys(data).length,
timestamp: new Date(),
userAgent: navigator.userAgent,
});
};

Validation Error Tracking

const trackValidationError = (fieldId: string, error: ValidationError) => {
analytics.track("validation_error", {
fieldId,
errorType: error.type,
errorMessage: error.message,
timestamp: new Date(),
});
};

Performance Monitoring

const measureRenderTime = (formId: string) => {
const startTime = performance.now();

return () => {
const endTime = performance.now();
const duration = endTime - startTime;

if (duration > 1000) {
console.warn(`Form ${formId} rendered slowly: ${duration}ms`);
}
};
};