Dynamic Forms V1 and V2
This page has multiple screenshots in the original Notion source (component titles, placeholders, etc.). Screenshots pending migration from Notion — see the Notion source for reference in the meantime.
Overview
- This document outlines the structure and configuration of the various form components used in the SDK.
- It is a reference for developers, designers, and stakeholders to understand how these components function and interact.
- Each form component is defined with a specific schema detailing its required and optional properties.
- The document covers the configs of all components in Dynamic Form V1 and Dynamic Form V2 (web components).
- Validation rules, event handling (
onClick,onChange,onValidated), and component behaviours are specified.
Purpose & use case
Who is this for? GTM teams, developers, support teams, SA/IEs, and anyone who wants to use the Dynamic Form module in their workflow config.
When should this be used? Whenever using Dynamic Form V1 and V2 (web components) in workflow config, or when adding components to a form V1/V2 module.
Dynamic Form V1
Core concepts
Structure of the module
-
propertiessections—JSONArray[required] — array of sections.id—String[required] — unique id for the section.components—JSONArray[required] — array of all components to render for the form.-
Event listeners (
onClick,onValidated, etc. — optional)reload— reload all default properties or reload only specific properties of any component within the same module.<componentId>— id of the component to reload. Either list the properties to reload (e.g.visible,enabled) or pass{}to reload the whole component.
Example:
"onClick": {
"reload": {
"resendContainer": {
"visible": "yes",
"enabled": "no"
},
"resendTimer": {}
}
}
-
-
persistState—String, defaults toyes. When set tono, the SDK does not display values entered previously.
Default properties by component type (for partial reload):
title: ['visible', 'text'],
description: ['visible', 'text'],
checkbox: ['visible', 'enabled', 'enable', 'required', 'text'],
date: ['visible', 'enabled', 'enable', 'required'],
dropDown: ['visible', 'required', 'enabled'],
file: ['visible', 'enabled', 'required'],
input: ['visible', 'enabled', 'required', 'value'],
hint: ['visible', 'text'],
textBlock: ['visible', 'text'],
visibleOnly: ['visible'], // loader, divider
container: ['visible', 'enabled'],
button: ['visible', 'enabled', 'loading', 'text'],
dateSpinner: ['visible', 'enable', 'required'],
image: ['visible', 'value'],
inputBlocks: ['visible', 'enabled', 'required'],
timer: ['visible', 'enabled'],
radio: ['visible', 'enabled', 'selected'],
chips: ['enabled', 'visible', 'selected'],
dynamicList: ['visible', 'data'],
Sample workflow module config
{
"type": "dynamicForm",
"subType": "form",
"id": "module_dynamicForm",
"nextStep": "",
"properties": {
"persistState": "no",
"sections": [
{
"id": "basicDetails",
"components": [
{
"id": "titleLabel",
"type": "label",
"subType": "title",
"text": "Enter basic details"
},
{
"id": "name",
"type": "text",
"subType": "singleLine",
"hint": "Enter name",
"title": "Name as per Govt. ID",
"enabled": "yes",
"visible": "yes",
"required": "yes",
"keyboard": "text",
"validation": [
{
"type": "regex",
"value": "^[a-zA-Z ]*$",
"errorMsg": "Please enter a valid name"
},
{
"type": "rule",
"value": "module_dynamicForm.name.value != ''",
"errorMsg": "Please enter a valid name"
}
],
"onValidated": {
"reload": {
"proceedButton1": {},
"proceedButton2": {
"enabled": "yes"
}
}
}
}
]
}
]
}
}
Frequently used component properties
These properties may not be applicable to all components. Properties for individual components are discussed in the next section.
Enabled
enabledtells whether the component should be interactable by the user or read-only.- Optional property, defaults to
yes. - Takes a static value (
yes/no) or a rule that evaluates toyes/no. - Examples:
enabled: yesorenabled: (id_card_validation.front.idNumber.confidence == 'low').
Visible
visibletells whether the component should be displayed.- Optional, defaults to
yes. - Static (
yes/no) or rule. - Examples:
visible: yesorvisible: (form.currentAddressSameAsPermanent.value == 'no').
Required
requiredtells whether the field is mandatory or optional.- Optional, defaults to
yes. - Static (
yes/no) or rule.
In Web SDK, required preliminarily decides the value of isValid property.
- If
requiredisyes, theisValidproperty of the same component isnoinitially. Later, based on validation added,isValidis set accordingly. - If
requiredisno,isValidis set toyes. - Having
required: yesdoes not automatically disable the next-step button until data is entered — the enable rule of the button has to be written based onrequiredandisValidto achieve that.
Validation
validationis an array of rules that should be satisfied for the value of a field to be valid.- Optional. By default no validation is done.
- Validation runs after user interacts with the field (typing then leaving, selecting from dropdown, etc.).
- Two types:
regexandrule.
Examples:
"validation": [{ "type": "regex", "value": "[\\w]+", "errorMsg": "" }]
"validation": [{ "type": "rule", "value": "(form.password.value == this.value)", "errorMsg": "" }]
"validation": [{ "type": "rule", "value": "(form.sameAddress.value == 'yes')", "errorMsg": "" }] // for checkboxes
"validation": [{ "type": "rule", "value": "(form.password.isValid == 'yes')", "errorMsg": "" }] // to check if field is not empty (required: yes) and validation passed
Value
- The initial value of the field when rendered.
- Can be empty string, a fixed string, a variable, or for dropdowns a value from the items array. For checkboxes,
yes/no. - Optional. Defaults:
""for most,no(unchecked) for checkboxes.
Technical details & workflows — component schemas
label
{
"id": "descLabel",
"type": "label",
"subType": "title",
"text": "This is sample text",
"visible": "yes"
}
Required:
id(String),typemust be"label".subType— one of"title","subTitle","textBlock","hint".text(String, can be empty).
Optional: visible, width, height (Fill/Wrap/numeric = pixels).
button
{
"id": "button_signature_capture",
"type": "button",
"subType": "primary",
"text": "Capture Cancelled Cheque",
"onClick": {
"nextStep": "module_cheque"
}
}
Required: id, type ("button"), text, subType (one of "primary", "secondary", "tertiary").
Optional: visible, enabled, width, height (Fill/Wrap/numeric).
Event handlers — onClick:
reload(object),reloadComponents(deprecated),nextStep(String).
Exposed property — value: not an input, but accessible in rules. yes once clicked, no by default.
text
{
"id": "addressLine1",
"type": "text",
"title": "House Number",
"required": "('yes' == 'yes')",
"keyboard": "text",
"value": "module_addressSplit.Line1",
"visible": "(module_common_show_address.perAddCorrect.value == 'N')",
"enabled": "(module_common_show_address.perAddCorrect.value == 'N')",
"validation": [
{
"type": "regex",
"value": "^(?=.*[a-zA-Z0-9])[a-zA-Z0-9,./ \\-]{1,120}$",
"errorMsg": "A number or letter is required. Only . , / - allowed. Limited to 120 characters"
}
],
"onValidated": {
"reload": { "proceedButton": {} }
}
}
Required: id, type ("text").
Optional: subType ("singleLine", "multiLine", "blocks"), title, hint, height/width, visible, value, enabled, required, keyboard ("text"/"number"/"email"/"phone").
Validation: array of { type: "regex" | "rule", value, errorMsg }.
Event handlers: onValidated, onChange — each with reload, deprecated reloadComponents, and nextStep.
date
{
"id": "grdian1dob",
"title": "Date Of Birth",
"hint": "Date Of Birth",
"type": "date",
"format": "dd-MM-yyyy",
"required": "yes",
"enabled": "yes",
"subType": "spinner",
"visible": "yes",
"dateRange": {
"startMonth": -1300,
"endMonth": -218,
"errorMsg": "Guardian must be atleast 18 years old"
},
"onValidated": {
"reloadComponents": { "button_id_jEbFxD": {} }
}
}
Required: id, type ("date").
Optional: subType ("spinner"/"default"), title, hint, dateRange ({startMonth, endMonth, errorMsg}), visible, format (combination of yyyy/YYYY/mm/MM/DD/dd), required, enabled, value, width/height, content (e.g., {{2}}-{{2}}-{{4}}).
Validation + event handlers: same as text.
dropdown
{
"id": "dropdown_id1",
"title": "Relationship with the Account Holder",
"hint": "Relationship with the Account Holder",
"type": "dropdown",
"items": ["defaultOption", "spouse", "son", "daughter"],
"labels": {
"defaultOption": "Select Option",
"spouse": "Spouse",
"son": "Son",
"daughter": "Daughter"
},
"value": "defaultOption",
"required": "lib_module.checkbox.value == 'yes'"
}
Required: id, type ("dropdown"), items (array), labels (object).
Optional: subType ("dropdown"), title, hint, value, visible, required, enabled, width/height.
Validation + event handlers: same pattern (onValidated, onChange).
checkbox
{
"id": "PEP",
"type": "checkbox",
"text": "I am not a Politically Exposed person (PEP)",
"required": "yes",
"value": "yes",
"onChange": { "reload": { "proceedButton": {} } }
}
Required: id, type ("checkbox"), text.
Optional: subType ("checkbox"), value ("yes"/"no"), required, visible, enabled, width/height.
Event handlers: onChange, onValidated.
file
{
"id": "statement",
"type": "file",
"subType": "file",
"version": "2",
"title": "Attach Proof",
"subTitle": "Overall size of files cannot be more than 5MB",
"helperTextIdle": "You can attach PDF, PNG or JPEGs",
"errorTextFile": "Error in files attached. Please attach them again",
"errorTextSizeMax": "Maximum allowed file size is 5MB",
"visible": "yes",
"enabled": "yes",
"required": "yes",
"maxFileSize": 5000,
"pickerTitle": "What file type are you attaching?",
"allowMultipleTypes": "no",
"supportedFiles": [
{ "type": "documents", "title": "PDF Document", "extensions": ["pdf"] },
{ "type": "images", "title": "Pictures or Images", "extensions": ["jpg", "jpeg", "png"] }
]
}
Required: id, type ("file"), subType ("file").
Optional: title, subTitle, errorTextFile, helperTextIdle, helperTextActive, errorTextSizeMax, pickerTitle, visible, maxFileSize, supportedFiles (array of { type: "documents" | "images" | "videos", title, extensions }), required, enabled, validation, onValidated, onChange, version ("1" or "2").
vertical and horizontal containers
{
"id": "step2Card",
"type": "vertical",
"subComponents": [
{ "id": "step2CardLabel", "type": "label", "subType": "title", "text": "Step 2: Read out the statements" }
]
}
Required: id, type ("vertical" or "horizontal").
Optional: subType (matching type), visible, enabled, width/height, text (for horizontal only), nextStep (horizontal only).
Event handlers: onClick with reload, reloadComponents, nextStep.
Nested components: subComponents (array).
radio
{
"id": "panRadio",
"type": "radio",
"enabled": "yes",
"value": "no",
"text": "PAN",
"onClick": {
"reload": {
"aadhaarRadio": { "value": "no" },
"aadhaarNumber": { "visible": "no" },
"PANNumber": { "visible": "yes" }
}
}
}
Required: id, type ("radio").
Optional: subType ("default"), enabled, visible, text, value, selected ("yes"/"no").
Event handlers: onClick.
chip
{
"id": "chip2",
"type": "chip",
"subType": "default",
"enabled": "yes",
"visible": "module_dynamicForm_17.dropDownCheckbox.value == 'no'",
"required": "yes",
"text": "Chip 2",
"value": "a"
}
Required: id, type ("chip"), subType ("default").
Optional: enabled, visible, text, value, selected ("yes"/"no").
Icons: leadingIcon, trailingIcon — each with imageUrl, selectedImageUrl, disabledImageUrl.
Event handlers: onClick.
list
{
"id": "cardSelectionGroup",
"type": "list",
"subType": "grid",
"numberOfColumns": "2",
"selectionMode": "single",
"value": { "text": "Aadhaar", "val": "aadhaar" },
"data": [
{ "text": "Aadhaar", "val": "aadhaar" },
{ "text": "PAN", "val": "pan" },
{ "text": "DL", "val": "dl" }
],
"itemsGenerator": {
"id": "cell",
"type": "horizontal",
"onClick": { "reload": { "cardSelectionGroup": {} } },
"subComponents": [
{
"id": "radio_button",
"type": "radio",
"subType": "default",
"value": "$item.val",
"text": "$item.text",
"selected": "$item.val == cardSelectionGroup.value.val"
}
]
}
}
Required: id, type ("list"), data, itemsGenerator.
Optional: subType ("vertical"/"grid"/"staggered"), selectionMode ("single"), numberOfColumns (required if subType is "grid"), visible, value.
divider
{ "id": "orLabel1", "type": "divider", "subType": "optional", "text": "OR" }
Required: id, type ("divider").
Optional: subType ("optional"), visible, text.
timer
{
"id": "messageTimer",
"type": "timer",
"subType": "countdown",
"enabled": "yes",
"visible": "no",
"duration": "5",
"onComplete": {
"reload": { "errorMessageContainer": { "visible": "no" } }
}
}
Required: id, type ("timer"), subType ("timer" or "countdown"), duration.
Optional: text, visible, enable.
Event handlers: onComplete.
loader
{ "id": "emailVerifyOtpLoader", "type": "loader", "subType": "loader", "visible": "no" }
Required: id, type ("loader"), subType ("loader").
Optional: visible, height, width.
image
{
"id": "arrowIcon2",
"type": "image",
"height": "10",
"value": "https://upskilling-sample-upload-2.s3.ap-south-1.amazonaws.com/arrorHigh.png"
}
Required: id, type ("image"), value (image URL).
Optional: subType ("image"), visible, height, width, onClick.
Dynamic Form V2 — Web Components
- Customisation limitations — while Dynamic Form V1 supports multiple components, its customisation options are limited. V2 allows full customisation, enabling users to build components as needed.
- Component flexibility — V1 comes with a fixed set of components, restricting scalability. V2 removes this limitation, allowing users to create any component with any style and functionality.
- Unlimited possibilities — V2 is not bound by predefined structures, offering limitless potential for customisation and adaptability.
Core concepts
Structure of the module
styles—String— holds all the styles for corresponding components in stringified format.scripts—JSONArray— external scripts needed to perform the desired action in the module.stylesheets—JSONArray— external stylesheets needed for the component.content—String[required] — holds HTML structure of the components; rendered as components on the screen.componentConfigs—JSONObject— holds the configs of individual components inside the module.
"<dom-id>": {
"sdkController": {
"visible": "<some-value>"
},
"dynamicHandlers": {
"children": ["<moduleId-of-child-modules>"],
"handlers": [
// same structure of reload obj here
]
},
"properties": {
"prop1": "<some-value>",
"prop2": "<some-value>"
},
"attributes": {
"disabled": "false",
"attr2": "<some-value>"
},
"events": {
"bl-input-change": {
"refresh": {
"attributes": ["atr1", "atr2"],
"properties": ["prop1", "prop2"]
},
"nextStep": "approve",
"reloadV2": {
"domId": {
"attributes": {},
"properties": { "prop": "value" }
}
}
}
}
}
Sample workflow module config
{
"type": "dynamicFormV2",
"subType": "formV2",
"id": "module_duKK2E_formV2",
"previousStep": "module_8tWz2Z_idcard_validation",
"nextStep": "",
"next_node_type": {
"hv_form_v2_5NedF6.events.retake-button-click.nextStep": "goto"
},
"properties": {
"styles": "#hv_form_v2_CXLzfi { border-radius: 6px; border: 1px solid #0000001A; align-items: center; margin: 8% 0% 0% 0%; } ...",
"scripts": [
"https://kycdev-hyperverge-co.s3.ap-south-1.amazonaws.com/audit-portal/stg/workflow-builder/componentLibTesting/bav1.js"
],
"content": "<button id=\"hv_form_v2_vk0sjN\"></button><div id=\"hv_form_v2_GsgoKv\">...</div>",
"stylesheets": [],
"componentConfigs": {
"hv_form_v2_vk0sjN": {
"attributes": {},
"properties": {
"textContent": "Disable OCR",
"componentConfigs": "[object Object]"
},
"events": {
"click": { "nextStep": "EXIT_POINT" }
},
"styles": {},
"sdkController": { "visible": "no" }
},
"hv_form_v2_kQe83Y": {
"attributes": {
"text": "Submit",
"font-weight": "600",
"background-color": "#554EF1",
"text-color": "white",
"border-color": "#554EF1"
},
"sdkController": { "enabled": "true" },
"events": {
"button-click": {
"refresh": { "properties": ["finalimgsrc", null] },
"nextStep": "module_disable_PassbookOCR"
}
}
},
"hv_form_v2_5NedF6": {
"attributes": {
"text": "Retake Image",
"background-color": "white",
"text-color": "#554EF1",
"border-color": "#554EF1"
},
"events": {
"retake-button-click": {
"refresh": {},
"nextStep": "module_8tWz2Z_idcard_validation"
}
}
}
},
"allowClose": true
},
"name": "PassBook Disable OCR Review Screen",
"superModuleType": "bav_verificationV4",
"superModuleId": ""
}
Technical details & workflows
For how to create and use web components using the builder and how it works, refer to the internal web-components builder documentation linked from the Notion source.