Component Actions in CXTMS
Introductionβ
Component Actions define the behavior of components in CXTMS. They handle events, fetch data, and perform various operations within the application.
When to Use Actionsβ
Use actions when you need to:
- Respond to user interactions (e.g., button clicks)
- Update data in the application
- Navigate between screens
- Display notifications or dialogs
- Provide audible or haptic feedback on supported devices
- Perform data validation
- Execute workflows or complex operations
Available Actionsβ
CXTMS provides the following actions:
- setVariables - Sets variables in the UI context
- setActionsVariables - Sets variables specifically for use within actions
- setParams - Sets parameters for the current Screen or Dialog (Query String)
- setStore - Updates values in the application's store
- setFields - Sets values for form fields
- query - Executes a GraphQL query
- mutation - Executes a GraphQL mutation
- workflow - Executes a predefined workflow
- navigate - Navigates to a different route
- navigateBackOrClose - Navigates back or closes the current dialog
- notification - Displays a notification message
- dialog - Opens a dialog component
- confirm - Shows a confirmation dialog
- setValue - Sets the value of a specific form field
- if - Conditionally executes actions
- validateForm - Validates the current form
- validateStore - Validates store variables
- fileUpload - Uploads a file to temporary storage
- fileDownload - Initiates a file download
- refresh - Refreshes the current screen or component
- setLocalStorage - Sets a value in local storage
- forEach - Iterates over an array and executes actions
- consoleLog - Logs a message to the console
- submitForm - Submits a form
- resetDirtyState - Resets the dirty state of a form
- setAIContext - Sets the AI context for the current screen
- createNewAIChat - Creates a new AI chat
- openBarcodeScanner - Opens a barcode scanning UI and handles scan events
- submitFormToExternalUrl - Submits form data to an external HTTP endpoint
- sound - Plays a sound
- vibrate - Vibrates the device
Let's explore each action in detail:
1. setVariablesβ
Sets variables in the UI context.
Attributes:
- [variable_name]: The name and value of each variable to set
- setVariables:
myForm.firstName: "John"
myForm.lastName: "Doe"
2. setActionsVariablesβ
Sets variables specifically for use within actions.
Attributes:
- [variable_name]: The name and value of each variable to set
- setActionsVariables:
firstName: "John"
lastName: "Doe"
3. setParamsβ
Sets parameters for the current Screen or Dialog.
Attributes:
- [param_name]: The name and value of each parameter to set
- setParams:
search: "John"
filter: "active"
4. setStoreβ
Updates values in the application's store.
Attributes:
- [store_path]: The path and new value to set in the store
- setStore:
myForm.firstName: "John"
myForm.lastName: "Doe"
5. setFieldsβ
Sets values for form fields.
Attributes:
- [field_name]: The name and new value for each form field
- setFields:
firstName: "John"
lastName: "Doe"
6. queryβ
Executes a GraphQL query.
Attributes:
- command: The GraphQL query string
- variables: An object containing query variables
- onSuccess: Actions to perform if the query is successful
- onError: Actions to perform if the query fails
- query:
command: "query { users { id name email }}"
variables: {}
onSuccess:
- setStore:
users: "{{ result.users }}"
onError:
- notification:
message: "Error fetching users"
7. mutationβ
Executes a GraphQL mutation.
Attributes:
- command: The GraphQL mutation string
- variables: An object containing mutation variables
- dirtyOnly: Submit only modified form fields (optional)
- onSuccess: Actions to perform if the mutation is successful
- onError: Actions to perform if the mutation fails
- mutation:
command: "mutation CreateUser($name: String!) { createUser(name: $name) { id name } }"
variables:
name: "John Doe"
onSuccess:
- notification:
message: "User created successfully"
onError:
- notification:
message: "Error creating user"
dirtyOnly β Partial Updatesβ
The dirtyOnly option filters mutation variables to include only form fields that were actually modified by the user. This is useful for PATCH-style updates where you want to avoid sending unchanged fields.
dirtyOnly accepts three formats:
| Value | Behavior |
|---|---|
true | Filter the entire variables object |
string | Dot-notation path to filter (e.g., "input.values") β keys outside the path are preserved |
object | { path: string, alwaysInclude?: string[] } β filter at path, but always include specified keys |
Example β Filter entire variables:
- mutation:
command: "mutation UpdateOrder($input: OrderInput!) { updateOrder(input: $input) { id } }"
variables:
input: "{{ form }}"
dirtyOnly: true
Example β Filter at a specific path:
- mutation:
command: "mutation UpdateOrder($id: Int!, $values: OrderValuesInput!) { updateOrder(id: $id, values: $values) { id } }"
variables:
id: "{{ id }}"
values: "{{ form }}"
dirtyOnly: "values"
Example β Filter with always-included keys:
- mutation:
command: "mutation UpdateContact($input: ContactInput!) { updateContact(input: $input) { id } }"
variables:
input: "{{ form }}"
dirtyOnly:
path: "input"
alwaysInclude:
- contactId
- organizationId
dirtyOnly works with React Hook Form's dirtyFields tracking. It only has effect when the mutation is triggered from within a form component. Fields that the user has not interacted with are excluded from the mutation variables.
8. workflowβ
Executes a predefined workflow.
Attributes:
- workflowId: The unique identifier of the workflow to execute
- inputs: An object containing input values for the workflow
- onSuccess: Actions to perform if the workflow completes successfully
- onError: Actions to perform if the workflow fails
- workflow:
workflowId: "f07103ce-d0b4-40fe-8a59-33eb851c8691"
inputs:
name: "John"
onSuccess:
- notification:
message: "Workflow completed"
onError:
- notification:
message: "Workflow failed"
9. navigateβ
Navigates to a different route in the application.
Attributes:
- to: The route path to navigate to
- navigate:
to: "/dashboard"
10. navigateBackOrCloseβ
Navigates back to the previous route or closes the current dialog.
Attributes:
- result: The result to pass back when closing a dialog (optional)
- navigateBackOrClose:
result: false
11. notificationβ
Displays a notification message.
Attributes:
- message: The notification message (can be localized)
- variant: The style variant of the notification (e.g., success, error, warning)
- notification:
message:
en-US: "This is a notification"
variant: success
12. dialogβ
Opens a dialog component.
Attributes:
- name: A unique identifier for the dialog
- props: Properties to pass to the dialog component
- onClose: Actions to perform when the dialog is closed
- component: The definition of the dialog component
- dialog:
name: createDialog
props:
title:
en-US: "Create New Item"
onClose:
- setStore:
myForm.firstName: "{{ result.firstName }}"
component:
# Dialog component definition here
13. confirmβ
Shows a confirmation dialog (available for form fields only).
Attributes:
- title: The title of the confirmation dialog
- message: The message to display in the dialog
- onConfirm: Actions to perform if the user confirms
- onCancel: Actions to perform if the user cancels
- confirm:
title: "Delete User"
message: "Are you sure you want to delete this user?"
onConfirm:
- mutation:
command: "mutation DeleteUser($id: ID!) { deleteUser(id: $id) }"
variables:
id: "{{ userId }}"
onCancel:
- notification:
message: "Deletion cancelled"
14. setValueβ
Sets the value of a specific form field (available for form fields only).
Attributes:
- field: The name of the field to set
- value: The new value for the field
- setValue:
field: "myForm.firstName"
value: "John"
15. ifβ
Conditionally executes actions based on a specified condition.
Attributes:
- condition: The condition to evaluate
- then: Actions to perform if the condition is true
- else: Actions to perform if the condition is false
- if: "{{ eval myForm.firstName === 'John' }}"
then:
- notification:
message: "Hello John!"
else:
- notification:
message: "Hello {{ myForm.firstName }}"
16. validateFormβ
Validates the current form fields against a specified schema or the default form schema.
Attributes:
- validationSchema: An object defining the validation rules for form fields. If not provided, the form will be validated against the default form schema.
- validateForm:
validationSchema: # optional
firstName:
required:
message: "First Name is required"
min:
length: 2
message: "First Name should be at least 2 characters"
17. validateStoreβ
Validates store variables against a specified schema.
Attributes:
- validationSchema: An object defining the validation rules for store variables
- validateStore:
validationSchema:
"myForm.email":
required:
message: "Email is required"
email:
message: "Invalid email format"
18. fileUploadβ
Uploads a file to temporary storage.
Attributes:
- accept: File types to accept (e.g., ".jpg,.png")
- maxSize: Maximum file size in MB
- multiple: Whether to allow multiple file uploads
- onSuccess: Actions to perform if the upload is successful
- onError: Actions to perform if the upload fails
- fileUpload:
accept: ".jpg,.png"
maxSize: 5
multiple: false
onSuccess:
- notification:
message: "File uploaded: {{ result.fileName }}"
onError:
- notification:
message: "Upload failed"
19. fileDownloadβ
Initiates a file download from a specified URL.
Attributes:
- url: The URL of the file to download
- fileDownload:
url: "https://example.com/files/document.pdf"
20. refreshβ
Refreshes the current screen or a specific component. Optionally pass highlight options to control how the target DataGrid highlights new/updated rows for this specific refresh.
Attributes:
- componentName: The name of the component to refresh (optional)
- options: Highlight options that override the target DataGrid's defaults for this refresh (optional)
- highlightNew: Whether to highlight newly added rows (boolean)
- highlightUpdated: Whether to highlight updated rows (boolean)
- highlightForRefreshes: Per-row TTL β number of refresh cycles a highlight persists (number)
# Simple refresh (backward compatible)
- refresh: "pickupOrders"
# Refresh with highlight options
- refresh: "pickupOrders"
options:
highlightNew: true
highlightForRefreshes: 3
# Refresh with highlighting disabled
- refresh: "pickupOrders"
options:
highlightNew: false
highlightUpdated: false
Options passed here override the target DataGrid's grid-level highlight defaults for this specific refresh cycle. If no options are provided, the DataGrid uses its own configured defaults. See DataGrid β Change Tracking & Row Highlights for details.
21. setLocalStorageβ
Sets a value in the browser's local storage.
Attributes:
- key: The key to use in local storage
- value: The value to store
- setLocalStorage:
key: "userPreferences"
value: "{{ userPreferences }}"
22. forEachβ
Iterates over an array and executes specified actions for each item.
Attributes:
- items: The array to iterate over
- item: The name to use for the current item in the iteration
- actions: The actions to perform for each item
- forEach:
items: "{{ myForm.items }}"
item: "currentItem"
actions:
- notification:
message: "Processing {{ currentItem.name }}"
23. consoleLogβ
Logs a message to the console.
Attributes:
- message: The message to log
- level: The log level (optional, defaults to "info". Other levels: "error", "warn", "debug", "log")
- consoleLog:
level: "info" # optional
message: "Hello World"
- consoleLog: "Hello World" # simplified version
24. submitFormβ
Submits a form. If the form name is not provided, the action will submit the form in which the button is placed. It's recommended to use submit form since it's reset dirty state of the form.
Attributes:
- formName: The name of the form to submit (optional, defaults to the name of the form component, in which the button is placed)
- submitForm:
formName: "myForm"
25. resetDirtyStateβ
Resets the dirty state of a form to false, indicating the form no longer has unsaved changes. Use this action when you want to programmatically mark a form as clean without submitting it, such as after a custom save operation or when discarding changes.
Attributes:
- formName: The name of the form to reset (optional, defaults to the current form context)
- resetDirtyState:
formName: "myForm"
Common use cases:
- After a successful custom save operation that doesn't use
submitForm - When implementing a "Discard Changes" button
- After programmatically reverting form values to their original state
Example with mutation:
- mutation:
command: "mutation SaveDraft($input: DraftInput!) { saveDraft(input: $input) { id } }"
variables:
input: "{{ myForm }}"
onSuccess:
- resetDirtyState:
formName: "myForm"
- notification:
message: "Draft saved"
variant: success
Best Practicesβ
- Use meaningful names for your actions to improve readability.
- Group related actions together for better organization.
- Use conditional actions (if) to handle different scenarios.
- Utilize setActionsVariables for temporary data that's only needed within the action sequence.
- Always handle both success and error cases in asynchronous actions (query, mutation, workflow).
- Use validateForm before submitting data to ensure data integrity.
- Leverage the forEach action for batch operations on arrays.
- Use
soundandvibratesparingly for high-signal events (scan success, mutation errors) rather than every button click. - Pair device feedback with a visual cue (
notification) so users who disable sound or vibration still get confirmation.
setAIContextβ
Sets the AI context for the current screen.
Attributes:
- entities: The entities to set in the AI context
- quickQuestions: The common questions to set in the AI context
- setAIContext:
entities:
- entityType: "{{ entityType }}"
entityName: "{{ entityName }}"
entityId: "{{ entityId }}"
displayText: "{{ entityName }}"
quickQuestions:
- "What is the name of the item?"
- "What is the description of the item?"
- "What is the price of the item?"
createNewAIChatβ
Creates a new AI chat. This action is used to create a new AI chat for the current screen. If the AI chat is closed, the action will open an AI window.
Attributes:
- title: The title of the AI chat
- topic: The topic of the AI chat
- entities: The entities to set in the AI chat
- quickQuestions: The quick questions to set in the AI chat
- question: The question to set in the AI chat
- autoExecute: Whether to automatically execute the AI chat (optional, defaults to false)
- createNewAIChat:
title: "My AI Chat"
topic: "{{ entityName }}"
entities:
- entityType: "{{ entityType }}"
entityName: "{{ entityName }}"
entityId: "{{ entityId }}"
displayText: "{{ entityName }}"
quickQuestions:
- "What is the name of the item?"
question: "What is the name of the item?"
autoExecute: true # optional, defaults to false
28. openBarcodeScannerβ
Opens a dedicated barcode scanning UI. Supports single-scan (default) and multi-scan flows. In multi-scan mode, the UI remains open until the user completes scanning or a maxBarcodes limit is reached.
Attributes:
- title: Optional title text for the scanner UI
- minBarcodeLength: Minimum length for recognized barcodes (defaults to 1 if omitted)
- allowMultiple: Whether to allow scanning multiple barcodes before closing (optional, defaults to false)
- maxBarcodes: Maximum number of barcodes to collect in multi-scan mode (optional). When set and
allowMultipleis true, the dialog auto-closes after this many scans - onScan: Actions to execute after each successful scan; receives
result.dataand, when available,result.format - onComplete: Actions to execute when the scanner UI finishes multi-scan and closes (user taps Done or
maxBarcodesreached). Receivesresult.barcodes(array of strings) - onClose: Actions to execute when the scanner UI is closed without completing (for example, user cancels). May include
result.barcodescollected so far if any
Notes:
- Single-scan (default): the dialog closes immediately after the first scan;
onScanruns once andonCompleteis not used. - Multi-scan (
allowMultiple: true):- Without
maxBarcodes, users close the dialog via the UI when finished;onCompletereceives all collected barcodes asresult.barcodes. - With
maxBarcodes, the dialog auto-closes when the limit is reached;onCompletereceives the final list asresult.barcodes.
- Without
result.formatmay vary by platform; guard its usage.
Single-scan example:
- openBarcodeScanner:
title: "Scan Item"
minBarcodeLength: 8
onScan:
- setStore:
scannedBarcode: "{{ result.data }}"
- notification:
message: "Scanned: {{ result.data }}"
onClose:
- notification:
message: "Scanner closed"
Multi-scan until user completes:
- openBarcodeScanner:
title: "Scan multiple items"
allowMultiple: true
minBarcodeLength: 8
onScan:
- notification:
message: "Captured: {{ result.data }}"
onComplete:
- setStore:
scannedBarcodes: "{{ result.barcodes }}"
- notification:
message: "Collected {{ result.barcodes.length }} barcodes"
Multi-scan with maximum count (auto-close):
- openBarcodeScanner:
title: "Scan up to 5 items"
allowMultiple: true
maxBarcodes: 5
minBarcodeLength: 8
onScan:
- notification:
message: "Added: {{ result.data }}"
onComplete:
- setStore:
scannedBarcodes: "{{ result.barcodes }}"
- notification:
message: "Scanning completed ({{ result.barcodes.length }} items)"
Conditional handling by format (single or multi-scan):
- openBarcodeScanner:
title: "Scan or log"
minBarcodeLength: 10
allowMultiple: true
maxBarcodes: 3 # optional
onScan:
- if:
condition: "{{ eval result.format === 'QR_CODE' }}"
then:
- navigate:
to: "/qr-details"
else:
- mutation:
command: "logBarcodeScan"
variables:
barcodeData: "{{ result.data }}"
format: "{{ result.format }}"
- notification:
message: "Barcode logged"
onComplete:
- notification:
message: "Finished scanning"
Integrating with a button:
component: button
props:
text: "Scan barcodes"
onClick:
- openBarcodeScanner:
title: "Scan Items"
allowMultiple: true
maxBarcodes: 10
minBarcodeLength: 8
onScan:
- consoleLog:
message: "Scanned: {{ result.data }}"
onComplete:
- setStore:
scannedBarcodes: "{{ result.barcodes }}"
- refresh: "dataGrid"
29. submitFormToExternalUrlβ
Submits form data to an external HTTP(S) endpoint. You can submit the values of an existing form by name (optionally remapping or excluding fields) or provide an explicit fields object. Useful for webhooks, public HTTP echo services, and simple REST endpoints.
Attributes:
- url: The destination URL to send the data to (supports template expressions)
- method: The HTTP method to use (e.g., "POST"). Defaults to "POST" if omitted
- target: Browser target for the submission (e.g., "_blank" to open a new tab)
- formName: Name of the form whose values will be submitted
- fields: Explicit key-value object to send instead of reading from a form
- formData: Object of key-value pairs to submit (supports template expressions). When used with formName, keys map to external field names and override/augment collected form values
- excludeFields: Array of internal field names to exclude from submission (applies when using formName)
- beforeSubmit: Actions to execute before the request is sent
- onSuccess: Actions to execute after a successful submission
- onError: Actions to execute if submission fails
Notes:
- Use either
formName(optionally withformData/excludeFields) or providefieldsexplicitly. url,fieldsvalues, and mappings support template expressions.- Setting
target: "_blank"opens the response in a new browser tab.
Simple submission to httpbin.org:
- submitFormToExternalUrl:
url: "https://httpbin.org/post"
method: "POST"
target: "_blank"
formName: "simpleTestForm"
onSuccess:
- notification:
type: success
message:
en-US: "Form submitted! Check the new browser tab to see the response."
With field mapping and exclusions:
- submitFormToExternalUrl:
url: "https://httpbin.org/post"
method: "POST"
target: "_blank"
formName: "mappingTestForm"
formData:
first_name: "{{ mappingTestForm.firstName }}"
last_name: "{{ mappingTestForm.lastName }}"
company: "{{ mappingTestForm.companyName }}"
phone: "{{ mappingTestForm.phoneNumber }}"
excludeFields:
- "internalNotes"
- "tempData"
onSuccess:
- notification:
type: success
message:
en-US: "Form submitted with field mapping! Internal fields excluded."
Dynamic URL (Webhook.site) with explicit fields:
- submitFormToExternalUrl:
url: "{{ webhookTestForm.webhookUrl }}"
method: "POST"
target: "_blank"
fields:
test_data_1: "{{ webhookTestForm.testData1 }}"
test_data_2: "{{ webhookTestForm.testData2 }}"
timestamp: "{{ format today 'yyyy-MM-dd HH:mm:ss' }}"
user_agent: "TMS Frontend Web - Test"
onSuccess:
- notification:
type: success
message:
en-US: "Submitted! Check webhook.site to see your data in real-time."
Complete flow with validation, pre-submit, and success handling:
# Step 1: Validate form (usually triggered before submit)
- validateForm:
formName: completeFlowForm
validationSchema:
customerName:
type: string
required:
message:
en-US: "Customer name is required"
customerEmail:
type: string
required:
message:
en-US: "Customer email is required"
productName:
type: string
required:
message:
en-US: "Product name is required"
# Step 2: Submit externally with mapping and lifecycle hooks
- submitFormToExternalUrl:
url: "https://httpbin.org/post"
method: "POST"
target: "_blank"
formName: "completeFlowForm"
formData:
order_id: "{{ completeFlowForm.orderNumber }}"
date_created: "{{ completeFlowForm.orderDate }}"
customer_full_name: "{{ completeFlowForm.customerName }}"
customer_email_address: "{{ completeFlowForm.customerEmail }}"
product_name: "{{ completeFlowForm.productName }}"
qty: "{{ completeFlowForm.quantity }}"
total_price: "{{ completeFlowForm.totalAmount }}"
order_notes: "{{ completeFlowForm.notes }}"
beforeSubmit:
- setStore:
lastSubmission:
orderNumber: "{{ completeFlowForm.orderNumber }}"
status: "submitting"
timestamp: "{{ today }}"
- notification:
type: info
message:
en-US: "Processing order {{ completeFlowForm.orderNumber }}..."
onSuccess:
- setStore:
lastSubmission:
orderNumber: "{{ completeFlowForm.orderNumber }}"
status: "submitted"
timestamp: "{{ today }}"
- notification:
type: success
message:
en-US: "Order {{ completeFlowForm.orderNumber }} submitted successfully!"
- navigateBackOrClose: {}
30. soundβ
Plays a short audible cue on the client device. Use it to confirm successful scans, validation outcomes, or other high-signal eventsβespecially in warehouse and mobile workflows where the user may not be looking at the screen.
Requires @cxtms/cx-schema 1.9.80+ for YAML validation. Older web and mobile client releases ignore these actions (safe no-op), so modules using them remain backward compatible.
Attributes:
- type: Preset sound to play (optional, defaults to
success). Supported values:success,error,warning,scan - volume: Playback volume from
0to1(optional, defaults to1)
Notes:
- On mobile, preset sounds map to platform-appropriate system or synthesized cues.
- On web/desktop, playback uses the browser audio layer when available; unsupported environments fail silently.
- Respects the device mute switch and browser autoplay policiesβif audio cannot play, the action completes without error and remaining actions in the chain continue.
- Does not display UI; combine with
notificationwhen users also need a visible message.
Simple preset (shorthand):
- sound: success
Object form with volume:
- sound:
type: error
volume: 0.8
Barcode scan success feedback:
- openBarcodeScanner:
title: "Scan Item"
minBarcodeLength: 8
onScan:
- sound: scan
- vibrate: success
- setStore:
scannedBarcode: "{{ result.data }}"
- notification:
message: "Scanned: {{ result.data }}"
type: success
Mutation error feedback:
- mutation:
command: "mutation ConfirmPick($id: Int!) { confirmPick(id: $id) { id } }"
variables:
id: "{{ pickId }}"
onSuccess:
- sound: success
- vibrate: success
onError:
- sound:
type: error
- vibrate:
type: error
- notification:
message: "Could not confirm pick"
type: error
31. vibrateβ
Triggers device vibration or haptic feedback. Use it alongside or instead of sound on phones and tabletsβfor example, to confirm a scan without relying on audio in noisy environments.
Requires @cxtms/cx-schema 1.9.80+ for YAML validation. Older web and mobile client releases ignore these actions (safe no-op), so modules using them remain backward compatible.
Attributes:
- type: Preset haptic pattern (optional, defaults to
success). Supported values:success,error,warning,light,medium,heavy - pattern: Custom vibration sequence as an array of milliseconds (optional). Follows the Vibration API convention: even-index elements (
0,2,4, β¦) are vibration durations; odd-index elements (1,3,5, β¦) are pauses. When set, overridestype. - duration: Single vibration pulse length in milliseconds (optional). Used when
patternis omitted and you need a simple one-shot pulse instead of a named preset.
Notes:
- On mobile,
success,error, andwarningmap to notification-style haptics;light,medium, andheavymap to impact-style haptics. - On web, uses
navigator.vibrate()when the browser and device support it. - On desktop or unsupported clients, the action is a no-op and the action chain continues.
- Some platforms ignore vibration when the device is in silent mode or low-power mode.
Simple preset (shorthand):
- vibrate: success
Named impact preset:
- vibrate:
type: heavy
Custom pattern (double pulse):
- vibrate:
pattern: [100, 50, 100]
Single-duration pulse:
- vibrate:
duration: 200
Multi-scan workflow with feedback:
- openBarcodeScanner:
title: "Scan up to 5 items"
allowMultiple: true
maxBarcodes: 5
minBarcodeLength: 8
onScan:
- sound: scan
- vibrate: light
- notification:
message: "Added: {{ result.data }}"
onComplete:
- sound: success
- vibrate: success
- setStore:
scannedBarcodes: "{{ result.barcodes }}"
Button click with subtle feedback:
component: button
props:
text: "Confirm Pick"
onClick:
- vibrate: light
- mutation:
command: "mutation ConfirmPick($id: Int!) { confirmPick(id: $id) { id } }"
variables:
id: "{{ pickId }}"
onSuccess:
- sound: success
- vibrate: success
- notification:
message: "Pick confirmed"
type: success
Related Topicsβ
- openBarcodeScanner β common source event for scan feedback
- notification β pair with sound/vibrate for visible confirmation
- if β branch feedback by scan result or validation outcome
- Barcode Scanner Component β scanner component and
onScancontext