Usage
This guide covers the essential patterns and practices for using FlowX.AI UI Toolkit components in your Angular or React application. Learn how to integrate process-driven components, handle data binding, and manage component lifecycle.
Core concepts
FlowX.AI UI Toolkit components connect your frontend directly to FlowX.AI process definitions. Understanding these core concepts helps you build effective process-driven applications:
Process container
The process container is the root component that manages a FlowX.AI process instance. It handles:
Process initialization and lifecycle
Communication with the FlowX.AI platform
State management and data synchronization
Navigation between process steps
Component data binding
Components automatically bind to process data defined in your process model. Data flows bidirectionally:
Process to UI: Process variables populate component values
UI to Process: User interactions update process variables
Process actions
User interactions trigger process actions that advance the workflow:
Button clicks execute process transitions
Form submissions validate and save data
Custom actions trigger business logic
Using the process container
The process container is your entry point for rendering FlowX.AI processes.
process-view.component.ts
import { Component , OnInit } from '@angular/core' ;
import { ActivatedRoute } from '@angular/router' ;
@ Component ({
selector: 'app-process-view' ,
template: `
<div class="process-wrapper">
<flx-process-container
[processName]="processName"
[processStartData]="startData"
(processStarted)="onProcessStarted($event)"
(processCompleted)="onProcessCompleted($event)"
(processError)="onProcessError($event)"
>
</flx-process-container>
</div>
` ,
styles: [ `
.process-wrapper {
padding: 20px;
max-width: 1200px;
margin: 0 auto;
}
` ]
})
export class ProcessViewComponent implements OnInit {
processName = 'customer-onboarding' ;
startData : any = {};
constructor ( private route : ActivatedRoute ) {}
ngOnInit () {
// Get initial data from route parameters
this . route . queryParams . subscribe ( params => {
this . startData = {
customerId: params [ 'customerId' ],
source: params [ 'source' ] || 'web'
};
});
}
onProcessStarted ( event : any ) {
console . log ( 'Process started:' , event . processInstanceId );
}
onProcessCompleted ( event : any ) {
console . log ( 'Process completed:' , event );
// Navigate to success page or show confirmation
}
onProcessError ( error : any ) {
console . error ( 'Process error:' , error );
// Show error message to user
}
}
import React , { useState , useEffect } from 'react' ;
import { useSearchParams } from 'react-router-dom' ;
import { ProcessContainer } from '@flowx/react-ui-toolkit' ;
export function ProcessView () {
const [ searchParams ] = useSearchParams ();
const [ startData , setStartData ] = useState ({});
const processName = 'customer-onboarding' ;
useEffect (() => {
// Get initial data from URL parameters
setStartData ({
customerId: searchParams . get ( 'customerId' ),
source: searchParams . get ( 'source' ) || 'web'
});
}, [ searchParams ]);
const handleProcessStarted = ( event : any ) => {
console . log ( 'Process started:' , event . processInstanceId );
};
const handleProcessCompleted = ( event : any ) => {
console . log ( 'Process completed:' , event );
// Navigate to success page or show confirmation
};
const handleProcessError = ( error : any ) => {
console . error ( 'Process error:' , error );
// Show error message to user
};
return (
< div className = "process-wrapper" >
< ProcessContainer
processName = { processName }
processStartData = { startData }
onProcessStarted = { handleProcessStarted }
onProcessCompleted = { handleProcessCompleted }
onProcessError = { handleProcessError }
/>
</ div >
);
}
Form components bind to process variables and handle validation automatically.
customer-form.component.ts
import { Component } from '@angular/core' ;
@ Component ({
selector: 'app-customer-form' ,
template: `
<form flxForm>
<flx-input
name="firstName"
label="First Name"
[required]="true"
[minLength]="2"
[maxLength]="50"
>
</flx-input>
<flx-input
name="lastName"
label="Last Name"
[required]="true"
>
</flx-input>
<flx-input
name="email"
label="Email Address"
type="email"
[required]="true"
[pattern]="emailPattern"
>
</flx-input>
<flx-select
name="country"
label="Country"
[options]="countries"
[required]="true"
>
</flx-select>
<flx-datepicker
name="dateOfBirth"
label="Date of Birth"
[maxDate]="maxBirthDate"
>
</flx-datepicker>
<flx-button
type="submit"
label="Continue"
actionName="CONTINUE"
>
</flx-button>
</form>
`
})
export class CustomerFormComponent {
emailPattern = / ^ [ a-zA-Z0-9._%+- ] + @ [ a-zA-Z0-9.- ] + \. [ a-zA-Z ] {2,} $ / ;
countries = [
{ value: 'US' , label: 'United States' },
{ value: 'UK' , label: 'United Kingdom' },
{ value: 'CA' , label: 'Canada' },
{ value: 'DE' , label: 'Germany' }
];
maxBirthDate = new Date (); // Today
}
import React from 'react' ;
import {
FlxForm ,
FlxInput ,
FlxSelect ,
FlxDatepicker ,
FlxButton
} from '@flowx/react-ui-toolkit' ;
export function CustomerForm () {
const emailPattern = / ^ [ a-zA-Z0-9._%+- ] + @ [ a-zA-Z0-9.- ] + \. [ a-zA-Z ] {2,} $ / ;
const countries = [
{ value: 'US' , label: 'United States' },
{ value: 'UK' , label: 'United Kingdom' },
{ value: 'CA' , label: 'Canada' },
{ value: 'DE' , label: 'Germany' }
];
const maxBirthDate = new Date (); // Today
return (
< FlxForm >
< FlxInput
name = "firstName"
label = "First Name"
required = { true }
minLength = { 2 }
maxLength = { 50 }
/>
< FlxInput
name = "lastName"
label = "Last Name"
required = { true }
/>
< FlxInput
name = "email"
label = "Email Address"
type = "email"
required = { true }
pattern = { emailPattern }
/>
< FlxSelect
name = "country"
label = "Country"
options = { countries }
required = { true }
/>
< FlxDatepicker
name = "dateOfBirth"
label = "Date of Birth"
maxDate = { maxBirthDate }
/>
< FlxButton
type = "submit"
label = "Continue"
actionName = "CONTINUE"
/>
</ FlxForm >
);
}
Form field names must match the process variable names defined in your FlowX.AI process model. The toolkit automatically handles data binding between the UI and process state.
Displaying process data
Use display components to show read-only process data.
order-summary.component.ts
import { Component } from '@angular/core' ;
@ Component ({
selector: 'app-order-summary' ,
template: `
<div class="summary-card">
<h2>Order Summary</h2>
<flx-text
name="orderNumber"
label="Order Number"
[bold]="true"
>
</flx-text>
<flx-text
name="orderDate"
label="Order Date"
format="date"
>
</flx-text>
<flx-text
name="totalAmount"
label="Total Amount"
format="currency"
[currency]="'USD'"
>
</flx-text>
<flx-table
name="orderItems"
[columns]="itemColumns"
>
</flx-table>
<flx-status-badge
name="orderStatus"
[statusMap]="statusColors"
>
</flx-status-badge>
</div>
`
})
export class OrderSummaryComponent {
itemColumns = [
{ field: 'name' , header: 'Item Name' },
{ field: 'quantity' , header: 'Quantity' },
{ field: 'price' , header: 'Price' , format: 'currency' }
];
statusColors = {
'pending' : 'warning' ,
'processing' : 'info' ,
'completed' : 'success' ,
'cancelled' : 'error'
};
}
import React from 'react' ;
import {
FlxText ,
FlxTable ,
FlxStatusBadge
} from '@flowx/react-ui-toolkit' ;
export function OrderSummary () {
const itemColumns = [
{ field: 'name' , header: 'Item Name' },
{ field: 'quantity' , header: 'Quantity' },
{ field: 'price' , header: 'Price' , format: 'currency' }
];
const statusColors = {
'pending' : 'warning' ,
'processing' : 'info' ,
'completed' : 'success' ,
'cancelled' : 'error'
};
return (
< div className = "summary-card" >
< h2 > Order Summary </ h2 >
< FlxText
name = "orderNumber"
label = "Order Number"
bold = { true }
/>
< FlxText
name = "orderDate"
label = "Order Date"
format = "date"
/>
< FlxText
name = "totalAmount"
label = "Total Amount"
format = "currency"
currency = "USD"
/>
< FlxTable
name = "orderItems"
columns = { itemColumns }
/>
< FlxStatusBadge
name = "orderStatus"
statusMap = { statusColors }
/>
</ div >
);
}
Handling process actions
Buttons and other interactive components trigger process actions.
action-buttons.component.ts
import { Component } from '@angular/core' ;
@ Component ({
selector: 'app-action-buttons' ,
template: `
<div class="action-bar">
<flx-button
label="Save Draft"
actionName="SAVE_DRAFT"
variant="secondary"
(actionExecuted)="onDraftSaved($event)"
>
</flx-button>
<flx-button
label="Cancel"
actionName="CANCEL"
variant="text"
[confirm]="{
title: 'Cancel Process',
message: 'Are you sure you want to cancel? All changes will be lost.'
}"
>
</flx-button>
<flx-button
label="Submit"
actionName="SUBMIT"
variant="primary"
[disabled]="!formValid"
[loading]="isSubmitting"
>
</flx-button>
</div>
`
})
export class ActionButtonsComponent {
formValid = false ;
isSubmitting = false ;
onDraftSaved ( event : any ) {
console . log ( 'Draft saved:' , event );
// Show success message
}
}
import React , { useState } from 'react' ;
import { FlxButton } from '@flowx/react-ui-toolkit' ;
export function ActionButtons () {
const [ formValid , setFormValid ] = useState ( false );
const [ isSubmitting , setIsSubmitting ] = useState ( false );
const handleDraftSaved = ( event : any ) => {
console . log ( 'Draft saved:' , event );
// Show success message
};
return (
< div className = "action-bar" >
< FlxButton
label = "Save Draft"
actionName = "SAVE_DRAFT"
variant = "secondary"
onActionExecuted = { handleDraftSaved }
/>
< FlxButton
label = "Cancel"
actionName = "CANCEL"
variant = "text"
confirm = { {
title: 'Cancel Process' ,
message: 'Are you sure you want to cancel? All changes will be lost.'
} }
/>
< FlxButton
label = "Submit"
actionName = "SUBMIT"
variant = "primary"
disabled = { ! formValid }
loading = { isSubmitting }
/>
</ div >
);
}
Conditional rendering
Show or hide components based on process state.
conditional-content.component.ts
import { Component } from '@angular/core' ;
@ Component ({
selector: 'app-conditional-content' ,
template: `
<div>
<flx-conditional
[when]="'applicationType'"
[equals]="'individual'"
>
<app-individual-form></app-individual-form>
</flx-conditional>
<flx-conditional
[when]="'applicationType'"
[equals]="'business'"
>
<app-business-form></app-business-form>
</flx-conditional>
<flx-conditional
[when]="'hasErrors'"
[equals]="true"
>
<flx-alert type="error" message="Please correct the errors above.">
</flx-alert>
</flx-conditional>
</div>
`
})
export class ConditionalContentComponent {}
import React from 'react' ;
import { FlxConditional , FlxAlert } from '@flowx/react-ui-toolkit' ;
import { IndividualForm } from './IndividualForm' ;
import { BusinessForm } from './BusinessForm' ;
export function ConditionalContent () {
return (
< div >
< FlxConditional
when = "applicationType"
equals = "individual"
>
< IndividualForm />
</ FlxConditional >
< FlxConditional
when = "applicationType"
equals = "business"
>
< BusinessForm />
</ FlxConditional >
< FlxConditional
when = "hasErrors"
equals = { true }
>
< FlxAlert
type = "error"
message = "Please correct the errors above."
/>
</ FlxConditional >
</ div >
);
}
Component lifecycle hooks
React to component and process lifecycle events.
lifecycle-example.component.ts
import { Component , OnInit , OnDestroy } from '@angular/core' ;
import { FlowxProcessService } from '@flowx/angular-ui-toolkit' ;
import { Subject , takeUntil } from 'rxjs' ;
@ Component ({
selector: 'app-lifecycle-example' ,
template: `<flx-process-container [processName]="processName"></flx-process-container>`
})
export class LifecycleExampleComponent implements OnInit , OnDestroy {
processName = 'my-process' ;
private destroy$ = new Subject < void >();
constructor ( private flowxProcess : FlowxProcessService ) {}
ngOnInit () {
// Subscribe to process state changes
this . flowxProcess . processState$
. pipe ( takeUntil ( this . destroy$ ))
. subscribe ( state => {
console . log ( 'Process state changed:' , state );
});
// Subscribe to process data changes
this . flowxProcess . processData$
. pipe ( takeUntil ( this . destroy$ ))
. subscribe ( data => {
console . log ( 'Process data updated:' , data );
});
}
ngOnDestroy () {
this . destroy$ . next ();
this . destroy$ . complete ();
}
}
import React , { useEffect } from 'react' ;
import { ProcessContainer , useFlowxProcess } from '@flowx/react-ui-toolkit' ;
export function LifecycleExample () {
const processName = 'my-process' ;
const { processState , processData } = useFlowxProcess ();
useEffect (() => {
console . log ( 'Process state changed:' , processState );
}, [ processState ]);
useEffect (() => {
console . log ( 'Process data updated:' , processData );
}, [ processData ]);
return (
< ProcessContainer processName = { processName } />
);
}
Best practices
Follow these patterns for optimal component usage:
Match field names: Ensure component name props match process variable names exactly
Handle errors gracefully: Always implement error handlers for process operations
Use TypeScript: Leverage type definitions for better development experience
Validate early: Use client-side validation to provide immediate feedback
Keep components focused: Break complex forms into smaller, reusable components
Test with real data: Use actual process instances during development
Next steps
Theming guide Customize component appearance to match your brand
Best practices Production-ready patterns and recommendations