Components are like building blocks. They allow you to build complex UIs and display business data using attribute models. The maximum number of components per screen is 50. Please refer to best practices for components.
The following components are supported:
This is the top level title of a page.
Parameter | Description |
---|---|
type (required) string | "TextHeading" |
text (required) string | Dynamic "${data.text}" |
visible Boolean |
Dynamic "${data.is_visible}" Default: True |
Parameter | Description |
---|---|
type (required) string | "TextSubheading" |
text (required) string | Dynamic "${data.text}" |
visible Boolean |
Dynamic "${data.is_visible}" Default: True |
Parameter | Description |
---|---|
type (required) string | TextBody |
text (required) string | Dynamic "${data.text}" |
font-weight enum |
{'bold','italic','bold_italic','normal'} Dynamic "${data.font_weight}" |
strikethrough Boolean | Dynamic "${data.strikethrough}" |
visible Boolean |
Dynamic "${data.is_visible}" Default: True |
markdown Boolean |
Default: False
Requires Flow JSON V5.1+ |
Parameter | Description |
---|---|
type (required) string | "TextCaption" |
text (required) string | Dynamic "${data.text}" |
font-weight enum |
{'bold','italic','bold_italic','normal'} Dynamic "${data.font_weight}" |
strikethrough Boolean | Dynamic "${data.strikethrough}" |
visible Boolean |
Dynamic "${data.is_visible}" Default: True |
markdown Boolean |
Default: False
Requires Flow JSON V5.1+ |
Component | Type | Limit / Restriction |
---|---|---|
Heading Subheading Body Caption | Character Limit | 80 80 4096 409 |
Heading Subheading Body Caption | Text | Empty or Blank value is not accepted |
Supported starting with Flow JSON version 5.1
In Flow JSON V5.1 TextBody
and TextCaption
also supports a limited markdown syntax. In order to enable this capability, set the property markdown=true
; this will instruct Whatsapp Flows to enable markdown syntax within these components.
{ "type": "TextBody", "markdown": true, "text": [ "This text is ~~***really important***~~", ] }
{ "type": "TextCaption", "markdown": true, "text": [ "This text is ~~***really important***~~", ] }
For comparison purposes, we show how the text components look like next to one another:
Supported starting with Flow JSON version 5.1
Flow JSON 5.1 introduces a new component - RichText
. The goal of the component is to provide a rich formatting capabilities and introduce the way to render large texts (Terms of Condition, Policy Documents, User Agreement and etc) without facing limitations of basic text components (TextHeading, TextSubheading, TextBody and etc)
Parameter | Description |
---|---|
type (required) string | "RichText" |
text (required) string | string array | Dynamic "${data.text}" |
visible Boolean |
Dynamic "${data.is_visible}" Default: True |
RichText
component utilizes a select subset of the Markdown
specification. It adheres strictly to standard Markdown
syntax without introducing any custom modifications. Content created for the RichText
component is fully compatible with standard Markdown
documents.
Note: The RichText component is designed to be used as a standalone component on the screen and cannot be combined with other components on the same screen.
The current syntax supports only Heading (h1)
and Subheading (h2)
. Other heading levels will be parsed but rendered as normal text - TextBody
.
Flow JSON | Flow Component |
---|---|
{ "type": "RichText", "text": [ "# Heading level 1", ] } |
|
{ "type": "RichText", "text": [ "## Heading level 2", ] } |
|
{ "type": "RichText", "text": [ "### Heading level 3", "#### Heading level 4", "##### Heading level 5", "###### Heading level 6", ] } |
|
To create paragraphs, split your text into different array items:
{ "type": "RichText", "text": [ "Paragraph 1", "Paragraph 2", ] }
or add a blank line in your markdown document that you bind using dynamic binding syntax ${data.your_dynamic_field}
# Heading 1 Paragraph 1 Paragraph 2
{ "type": "RichText", "text": "${data.text}" }
Flow JSON | Flow Component |
---|---|
{ "type": "RichText", "text": [ "Let’s make a **bold** statement", ] } |
|
{ "type": "RichText", "text": [ "Let's make this text *italic*", ] } |
|
{ "type": "RichText", "text": [ "Let's make this text ~~Strikethrough~~", ] } |
|
{ "type": "RichText", "text": [ "This text is ~~***really important***~~", ] } |
|
You can organize items into ordered and unordered lists. At the moment, only single level lists are supported.
Flow JSON | Flow Component |
---|---|
{ "type": "RichText", "text": [ "1. Item 1", "2. Item 2", "3. Item 3" ] } |
|
{ "type": "RichText", "text": [ "- Item 1", "- Item 2", "- Item 3" ] } { "type": "RichText", "text": [ "+ Item 1", "+ Item 2", "+ Item 3" ] } |
|
You can also include images in the content. Please note, external URIs are not supported and you can only include base64 inline images
{ "type": "RichText", "text": ["![Image alt text](data:image/png;base64,<base64 content>)"] }
Recommended image formats:
To create a link, enclose the link text in brackets and then follow it immediately with the URL in parentheses
{ "type": "RichText", "text": [ "[Whatsapp Flows are awesome](https://business.whatsapp.com/products/whatsapp-flows)", ] }
To add a table, use three or more hyphens (---) to create each column’s header, and use pipes (|) to separate each column. For compatibility, you should also add a pipe on either end of the row.
Cell content can be combined with the following syntax:
{ "type": "RichText", "text": [ "| Column Header 1 | Column Header 2 |", "| ------------- | ------------- |", "| **Bold** text 1 | [Link](<URI>) |", "| **Bold** text 1 | ![Image alt text](data:image/png;base64,<base64 content>) |", ] }
Width of the columns:
Width of the column is based on the Header content size. Markdown specification doesn’t provide a specific syntax for controlling a column width. If you want to make a certain column wider, simply add additional content to the header:
{ "type": "RichText", "text": [ "| Column Header 1 - Extended width | Column Header 2 |", "| ------------- | ------------- |", "| **Bold** text 1 | Cell text 2 |", ] }
If your text content for markdown has a limited size, you can incorporate it as a static text as shown in all examples above, however if your text is large and you expect to update it often on your server, we recommend sending it as a part of dynamic data, this will improve overall readability of the JSON and allow to load always up to date text from your server.
Please note: We use array text property for static cases since it’s easier to read. However the components support both types: Array of strings
and string
. Your markdown can be sent as a normal string, you don’t need to convert it to an array of strings.
Here is the quick overview of the syntax that’s supported by RichText, TextBody and TextCaption components
Syntax | RichText | TextBody | TextCaption |
---|---|---|---|
| ✅ | ❌ | ❌ |
| ✅ | ❌ | ❌ |
| ✅ | ✅ | ✅ |
| ✅ | ✅ | ✅ |
| ✅ | ✅ | ✅ |
| ✅ | ✅ | ✅ |
| ✅ | ✅ | ✅ |
| ✅ | ✅ | ✅ |
| ✅ | ✅ | ✅ |
| ✅ | ❌ | ❌ |
| ✅ | ❌ | ❌ |
Parameter | Description |
---|---|
type (required) string | "TextInput" |
label (required) string | Dynamic "${data.label}" |
input-type enum | {'text','number','email', 'password', 'passcode', 'phone'} |
pattern String |
When specified, it is a regular expression which the input's value must match for the value to pass.
|
required Boolean | Dynamic "${data.is_required}" |
min-chars String | Dynamic "${data.min_chars}" |
max-chars String |
Dynamic "${data.max_chars}". Default value is 80 characters. |
helper-text String | Dynamic "${data.helper_text}" |
name (required) String | |
visible Boolean |
Dynamic "${data.is_visible}" Default: True |
init-value String |
Dynamic "${data.init-value}" Only available when component is outside Form component Optional Form |
error-message String |
Dynamic "${data.error-message}" Only available when component is outside Form component Optional Form |
Parameter | Description |
---|---|
type (required) string | "TextArea" |
label (required) string | Dynamic "${data.label}" |
required Boolean | Dynamic "${data.is_required}" |
max-length String |
Dynamic "${data.max_length}" Default value is 600 characters. |
name (required) String | |
helper-text String | Dynamic "${data.helper_text}" |
enabled Boolean | Dynamic "${data.is_enabled}" |
visible Boolean |
Dynamic "${data.is_visible}" Default: True |
init-value String |
Dynamic "${data.init-value}" Only available when component is outside Form component Optional Form |
error-message String |
Dynamic "${data.error-message}" Only available when component is outside Form component Optional Form |
Component | Type | Limit / Restriction |
---|---|---|
TextInput | Helper Text Error Text Label | 80 characters 30 characters 20 characters |
TextArea | Helper Text Label | 80 characters 20 characters |
Together, the text entry components look like as shown:
CheckboxGroup component allows users to pick multiple selections from a list of options.
Parameter | Description |
---|---|
type (required) string | "CheckboxGroup" |
data-source (required) Array |
Dynamic "${data.data_source}"
Flow JSON versions before 5.0: Flow JSON versions after 5.0: Flow JSON versions after 6.0: |
name (required) String | |
min-selected-items Integer | Dynamic "${data.min_selected_items}" |
max-selected-items Integer | Dynamic "${data.max_selected_items}" |
enabled Boolean | Dynamic "${data.is_enabled}" |
label string |
Dynamic "${data.label}"
|
required Boolean | Dynamic "${data.is_required}" |
visible Boolean |
Dynamic "${data.is_visible}" Default: True |
on-select-action Action |
update_data |
on-unselect-action Action |
Only `update_data` is supported.
|
description String |
Dynamic "${data.description}"
|
init-value Array<String> |
Dynamic "${data.init-value}" Only available when component is outside Form component |
error-message String |
Dynamic "${data.error-message}" Only available when component is outside Form component |
media-size enum |
{'regular', 'large'} Dynamic "${data.media-size}" |
Images in WEBP format are not supported on iOS versions prior to iOS 14.
For the data-source
field, you can declare it dynamically or statically.
This static example hardcodes the respective id
's and title
's for the data-source
field.
In this dynamic example, you can see that data-source
references the days_per_week_options
of type array
defined before it using days_per_week_options
. When defining such a structure, you need to specify items
in the array
, which will be of type object
. Then inside the items
object, you have a properties
dictionary with id
and title
just like in the static declaration. Both id
and title
will always be of type String
. Within the days_per_week_options
array, you must define concrete examples in the __example__
field.
Type | Limit / Restriction |
---|---|
Label Content Title Description Metadata Min # of options Max # of options Image | 30 Characters 30 Characters 300 Characters 20 Characters 1 20 Flow JSON versions before 6.0: 300KB Flow JSON versions after 6.0:100KB |
Parameter | Description |
---|---|
type (required) string | "RadioButtonsGroup" |
data-source (required) Array |
Dynamic "${data.data_source}"
Flow JSON versions before 5.0: Flow JSON versions after 5.0: Flow JSON versions after 6.0: |
name (required) String | |
enabled Boolean | Dynamic "${data.is_enabled}" |
label string |
Dynamic "${data.label}"
|
required Boolean | Dynamic "${data.is_required}" |
visible Boolean |
Dynamic "${data.is_visible}" Default: True |
on-select-action Action |
update_data |
on-unselect-action Action |
Only `update_data` is supported.
|
description String |
Dynamic "${data.description}"
|
init-value Array<String> |
Dynamic "${data.init-value}" Only available when component is outside Form component |
error-message String |
Dynamic "${data.error-message}" Only available when component is outside Form component |
media-size enum |
{'regular', 'large'} Dynamic "${data.media-size}" |
Images in WEBP format are not supported on iOS versions prior to iOS 14.
For the data-source
field, you can declare it dynamically or statically.
This static example hardcodes the respective id
's and title
's for the data-source
field.
In this dynamic example, you can see that data-source
references the experience_level_options
of type array
defined before it using data.experience_level_options
. When defining such a structure, you need to specify items
in the array
, which will be of type object
. Then inside the items
object, you have a properties
dictionary with id
and title
just like in the static declaration. Both id
and title
will always be of type String
. Within in the experience_level_options
array you must define concrete examples in the __example__
field.
Type | Limit / Restriction |
---|---|
Label Content Title Description Metadata Min # of options Max # of options Image | 30 Characters 30 Characters 300 Characters 20 Characters 1 20 Flow JSON versions before 6.0: 300KB Flow JSON versions after 6.0:100KB |
Parameter | Description |
---|---|
type (required) string | "Footer" |
label (required) string | Dynamic "${data.label}" |
left-caption String |
Dynamic "${data.left_caption}"
Can set left-caption and right-caption or only center-caption, but not all 3 at once |
center-caption String |
Dynamic "${data.center_caption}"
Can set center-caption or left-caption and right-caption, but not all 3 at once |
right-caption String |
Dynamic "${data.right_caption}"
Can set right-caption and left-caption or only center-caption, but not all 3 at once |
enabled Boolean | Dynamic "${data.is_enabled}" |
on-click-action (required) Action | Action |
Type | Limit / Restriction |
---|---|
Label Max Character Limit Captions Max Character Limit | 35 15 |
Parameter | Description |
---|---|
type (required) string | "OptIn" |
label (required) string | Dynamic "${data.label}" |
required Boolean | Dynamic "${data.is_required}" |
name (required) String | |
on-click-action Action |
Action that is executed on clicking "Read more".
"Read more" is only visible when an on-click-action is specified. Allowed values are |
on-select-action Action |
Only `update_data` is supported.
|
on-unselect-action Action |
Only `update_data` is supported.
|
visible Boolean |
Dynamic "${data.is_visible}" Default: True |
init-value Boolean |
Dynamic "${data.init-value}" Only available when component is outside Form component Optional Form |
Type | Limit / Restriction |
---|---|
Content Max Character Limit Max number of Opt-Ins Per Screen | 120 5 |
Parameter | Description |
---|---|
type (required) string | "Dropdown" |
label (required) string | |
data-source (required) Array |
Dynamic "${data.data_source}"
Flow JSON versions before 5.0: Flow JSON versions after 5.0: Flow JSON versions after 6.0: |
required Boolean | |
enabled Boolean | Dynamic "${data.is_enabled}" |
required Boolean | Dynamic "${data.is_required}" |
visible Boolean |
Dynamic "${data.is_visible}" Default: True |
on-select-action Action |
update_data |
on-unselect-action Action |
Only `update_data` is supported.
|
init-value String |
Dynamic "${data.init-value}" Only available when component is outside Form component |
error-message String |
Dynamic "${data.error-message}" Only available when component is outside Form component |
Images in WEBP format are not supported on iOS versions prior to iOS 14.
Type | Limit / Restriction |
---|---|
Label Title Min dropdown options Max dropdown options Description Metadata Image | 20 characters 30 characters 1 200 if no images are present in the 300 characters 20 characters Flow JSON versions before 6.0: 300KB Flow JSON versions after 6.0:100KB |
For the data-source
field, you can declare it dynamically or statically.
This static example hardcodes the respective id
's and title
's for the data-source
field.
In this dynamic example, you can see that data-source
references the experience_level_options
of type array
defined before it using experience_level_options
. When defining such a structure, you need to specify items
in the array
, which will be of type object
. Then inside the items
object, you have a properties
dictionary with id
and title
just like in the static declaration. Both id
and title
will always be of type String
. Within the experience_level_options
array you must define concrete examples in the __example__
field.
Parameter | Description |
---|---|
type (required) string | "EmbeddedLink" |
text (required) string | Dynamic "${data.text}" |
on-click-action (required) Action |
Action
Allowed values are |
visible Boolean |
Dynamic "${data.is_visible}" Default: True |
Type | Limit / Restriction |
---|---|
Character limit | 25 |
Case | Sentence case |
Max Number of Embedded Links Per Screen | 2 |
Text | Empty or Blank value is not accepted |
The DatePicker component allows users to input dates through an intuitive date selection interface.
Parameter | Description |
---|---|
type (required) string | "DatePicker" |
label (required) string | Dynamic "${data.label}" |
min-date String (timestamp in milliseconds) | Dynamic "${data.min_date}". Please refer to section Guidelines for Usage |
max-date String (timestamp in milliseconds) | Dynamic "${data.max_date}". Please refer to section Guidelines for Usage |
name (required) string | |
unavailable-dates Array < timestamp in milliseconds: String > | Dynamic "${data.unavailable_dates}". Please refer to section Guidelines for Usage |
visible Boolean |
Dynamic "${data.is_visible}" Default: True |
helper-text String | Dynamic "${data.helper_text}" |
enabled Boolean |
Dynamic "${data.is_enabled}" Default: True |
on-select-action Action | Only `data_exchange` is supported. |
init-value String |
Dynamic "${data.init-value}" Only available when component is outside Form component Optional Form |
error-message String |
Dynamic "${data.error-message}" Only available when component is outside Form component Optional Form |
Payload that is sent to a data channel business endpoint is a string which shows the timestamp in milliseconds.
Due to current system limitations, the DatePicker functions correctly and as intended(that is, correct selection range is shown to the User, and accurate user-selection value is returned to the Business) as long as
Correct behavior is not guaranteed if businesses and end-users are in different time zones. For example, if a business operating in Sao Paulo (UTC-3) sends a Flow to a user in Manaus (UTC-4), the DatePicker may not work as expected. We don't recommend using it if your users are in different time zones than you.
DatePicker allows setting of date range for user selection through min-dates
and max-dates
fields, and also prevents selection of specific dates using the unavailable-dates
field. If you have not supplied the date range , then by default, the component allows the user to select dates from 1 January 1900
to 31 December 2100
.
Setting Date Parameters in the Component
When you specify the date range or set unavailable dates, you should convert your local dates with midnight (00:00:00) as a base time to UTC timestamps.
For example, if you are a business based in India who wants to collect a date in the range 21 March 2024
to 25 March 2024
, then you should set min-dates
and max-dates
as 1710958020000
and 1711303620000
, respectively.
21 March 2024, 00:00:00.000 IST
converts to 20 March 2024, 18:30:00.000 UTC
which is represented by timestamp 1710958020000
.
25 March 2024, 00:00:00.000 IST
converts to 24 March 2024, 18:30:00.000 UTC
which is represented by timestamp 1711303620000
.
Component Integration
DatePicker will read the timestamps in min-dates
, max-dates
and unavailable-dates
fields and convert it to the end user's local date for displaying on the UI. In the example we discussed above, a user in India will see dates from 21 March 2024
to 25 March 2024
in the DatePicker component.
Processing User Selection
Businesses will receive a UTC timestamp, which should be converted back to the business's local time zone. Importantly, businesses should focus solely on the date portion of the resulting timestamp , disregarding the time portion. This ensures that the date remains consistent with the user's selection. Unfortunately, this conversion will only work correctly when the business and user are in the same time zone.
For example, if you receive a timestamp 1711013400000
then convert it to your local timezone and extract the date. If you are in IST, the timestamp will convert to 21 March 2024 15:00 IST
, and you should treat 21st March 2024
as the user selected date.
If you need to send flow messages to users in time zones different from yours despite reviewing the above guidelines, follow these steps to overcome the limitation:
UTC-2 (Fernando de Noronha)
to UTC-5 (Rio Branco)
.Dropdown
component within your Flow that allows users to select their current time zone.UTC-5
.March 20th, 2024
to March 25th, 2024
, then provide the timestamp in milliseconds for March 20th, 2024 at 5 AM UTC
and March 25th, 2024 at 5 AM UTC
.1710910800000
, then convert it to UTC-3
to get March 20th, 2024
.DatePicker component has been updated to use a formatted date string in the format "YYYY-MM-DD", such as "2024-10-21", for setting and retrieving date values. This update makes the date values of the date picker unrelated to time zones, allowing businesses to send messages and collect dates from users in any time zone in a consistent manner.
Type | Limit / Restriction |
---|---|
Label Max Length | 40 characters |
Helper Text Max Length | 80 characters |
Error Message Max Length | 80 characters |
Supported starting with Flow JSON version 6.1
The CalendarPicker component allows users to select a single date or a range of dates from a full calendar interface.
Parameter | Description |
---|---|
type (required) String | "CalendarPicker" |
name (required) String | |
title String |
Dynamic "${data.title}" Only available when 'mode' is set to 'range' |
description String |
Dynamic "${data.description}" Only available when 'mode' is set to 'range' |
label (required) String |
Dynamic "${data.label}" When 'mode' is set to 'range' the value should be in '{"start-date": String, "end-date": String}' format |
helper-text String |
Dynamic "${data.helper_text}" When 'mode' is set to 'range' the value should be in '{"start-date": String, "end-date": String}' format |
required Boolean |
Dynamic "${data.is_required}" Default: False When 'mode' is set to 'range' the value should be in '{"start-date": Boolean, "end-date": Boolean}' format |
visible Boolean |
Dynamic "${data.is_visible}" Default: True |
enabled Boolean |
Dynamic "${data.is_enabled}" Default: True |
mode enum |
{"single", "range"} Dynamic "${data.mode}" Default: "single" Allows to select one date in 'single' mode or start and end dates in 'range' mode |
min-date String |
Dynamic "${data.min_date}" Formatted date string in the format "YYYY-MM-DD" Disallows selecting dates before specified min-date |
max-date String |
Dynamic "${data.max_date}" Formatted date string in the format "YYYY-MM-DD" Disallows selecting dates after specified max-date |
unavailable-dates Array<String> |
Dynamic "${data.unavailable_dates}" Formatted date strings in the format "YYYY-MM-DD" Disallows selecting specific dates, should be in the range between min-date and max-date if specified |
include-days Array<enum> |
{"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"} Dynamic "${data.include_days}" Default: all weekdays - ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"] Enables specific weekdays, for example to enable only working days Monday through Friday and disallow selecting Saturdays and Sundays |
min-days Integer |
Dynamic "${data.min_days}" Available only in 'range' mode to set the minimum number of days between start and end dates |
max-days Integer |
Dynamic "${data.max_days}" Available only in 'range' mode to set the maximum number of days between start and end dates |
on-select-action Action |
Only 'data_exchange' is supported. Payload that is sent to a data channel business endpoint is a string in "YYYY-MM-DD" format for 'single' mode or dictionary in {"start-date":"YYYY-MM-DD","end-date":"YYYY-MM-DD"} format for 'range' mode |
init-value String |
Dynamic "${data.init-value}" When 'mode' is set to 'range' the value should be in '{"start-date": String, "end-date": String}' format Only available when component is outside Form component |
error-message String |
Dynamic "${data.error-message}" When 'mode' is set to 'range' the value should be in '{"start-date": String, "end-date": String}' format Only available when component is outside Form component |
Type | Limit / Restriction |
---|---|
Title Max Length | 80 characters |
Description Max Length | 300 characters |
Label Max Length | 40 characters |
Helper Text Max Length | 80 characters |
Error Message Max Length | 80 characters |
Parameter | Description |
---|---|
type (required) string | "Image" |
src (required) string |
Base64 of an image. Dynamic "${data.src}" |
width Integer | Dynamic "${data.width}" |
height Integer | Dynamic "${data.height}" |
scale-type string |
`cover` or `contain` Default value: `contain` |
aspect-ratio Number |
Default value: 1 Dynamic "${data.aspect_ratio}" |
alt-text string |
Alternative Text is for the accessibility feature, eg. Talkback and Voice over Dynamic "${data.alt_text}" |
Scale Type | Description |
---|---|
| Image is clipped to fit the image container. If there is no height value (which is the default), the image will be displayed to its full width with its original aspect ratio. If the height value is set, the image is cropped within the fixed height. Depending on the image whether it is portrait or landscape, image is clipped vertically or horizontally. |
| Image is contained within the image container with the original aspect ratio. If there is no height value (which is the default), the image will be displayed to its full width with its original aspect ratio. If the height value is set, the image is contained in the image container with the fixed height and the original aspect ratio. Developers should consider setting a specific height, width and aspect ratio for images whenever using |
Type | Limit / Restriction |
---|---|
Max number of images per screen Recommended image size Total data channel payload size Supported images formats | 3 Up to 300kb 1 Mb JPEG PNG |
Supported starting with Flow JSON version 4.0
Parameter | Description |
---|---|
type (required) string | "If" |
condition (required) string |
Boolean expression, it allows both dynamic and static data. Check section below for more info. |
then (required) Array of Components | The components that will be rendered when `condition` is `true`. Allowed components: "TextHeading", "TextSubheading", "TextBody", "TextCaption", "CheckboxGroup", "DatePicker", "Dropdown", "EmbeddedLink", "Footer", "Image", "OptIn", "RadioButtonsGroup", "Switch", "TextArea", "TextInput" and "If"*. It is allowed to nest up to 3 "If" components. |
else Array of Components | The components that will be rendered when `condition` is `false`. Allowed components: "TextHeading", "TextSubheading", "TextBody", "TextCaption", "CheckboxGroup", "DatePicker", "Dropdown", "EmbeddedLink", "Footer", "Image", "OptIn", "RadioButtonsGroup", "Switch", "TextArea", "TextInput" and "If"*. It is allowed to nest up to 3 "If" components. |
Operator | Symbol | Types allowed | Description and examples |
---|---|---|---|
|
|
| It is used to define the precedence of operations. Or if you want to perform boolean operations that one of the sides is a result of a number or string comparison. It always require an operation within it. One expression can contain multiple parentheses. Examples:
|
|
|
| It is used to compare booleans, numbers and strings. Both sides should have the same type and at least one of them should contain a dynamic variable. Examples:
|
|
|
| It is used to compare booleans, numbers and strings. Both sides should have the same type and at least one of them should contain a dynamic variable. Examples:
|
|
|
| It performs the boolean
|
|
|
| It performs the boolean
|
|
|
| It performs the boolean
|
|
|
| It is used to compare to numbers. At least one of them should be a dynamic variable. Examples:
|
|
|
| It is used to compare to numbers. At least one of them should be a dynamic variable. Examples:
|
|
|
| It is used to compare to numbers. At least one of them should be a dynamic variable. Examples:
|
|
|
| It is used to compare to numbers. At least one of them should be a dynamic variable. Examples:
|
${data...}
or ${form...}
). Footer
can be added within If
only in the first level, not inside a nested If
.Footer
within If
, it should exist in both branches (i.e. then
and else
). This means that else
becomes mandatory.Footer
within If
it cannot exist a footer outside, because the max count of Footer
is 1 per screen.The table below show examples of limitations and validation errors that will be shown for certain cases.
Scenario | Validation error shown |
---|---|
| Missing Footer inside one of the if branches. Branch "else" should exist and contain one Footer. |
| Missing Footer inside one of the if branches. |
| Missing Footer inside one of the if branches. |
| You can only have 1 Footer component per screen. |
| Invalid value found at: "$root/screens/path_to_your_component/then" due to empty array. It should contain at least one component. |
Supported starting with Flow JSON version 4.0
Parameter | Description |
---|---|
type (required) string | "Switch" |
value (required) string | A variable that will have its value evaluated during runtime. Example - `${data.animal}` |
cases (required) Map of Array of Components | Each property is a key (string) that maps to an Array of Components. When the `value` matches the key, it renders its array of components. Allowed components: "TextHeading", "TextSubheading", "TextBody", "TextCaption", "CheckboxGroup", "DatePicker", "Dropdown", "EmbeddedLink", "Footer", "Image", "OptIn", "RadioButtonsGroup", "TextArea", "TextInput". |
"cases": {}
) The table below show examples of limitations and validation errors that will be shown for certain cases.
Scenario | Validation error shown |
---|---|
| Invalid empty property found at: "$root/screens/path_to_your_component/cases". |
Please refer to the specific page for media upload components.
Supported from Flows v6.2+.
The NavigationList component allows users to navigate effectively between different screens in a Flow, by exploring and interacting with a list of options. Each list item can display rich content such as text, images and tags.
Parameter | Description |
---|---|
type (required) string | "NavigationList" |
name (required) string | |
list-items (required) array | Dynamic "${data.list_items}" |
label string | Dynamic "${data.label}" |
description string | Dynamic "${data.description}" |
media-size enum |
{'regular','large'} Default: 'regular' Dynamic "${data.media-size}" |
on-click-action action | `data_exchange` and `navigate` are supported. |
Each item in the list of items supports the following properties:
Parameter | Description |
---|---|
main-content (required) object |
|
end object |
|
start object |
|
badge string | |
tags Array<string> | |
on-click-action action | `data_exchange` and `navigate` are supported. |
Images in WEBP format are not supported on iOS versions prior to iOS 14.
The on-click-action
is required for the component, and it can be defined either:
In this dynamic example, you can see that list-items
references the insurances
of type array
defined before it using insurances
. When defining such a structure, you need to specify items
in the array
, which will be of type object
. Then inside the items
object, you have a properties
dictionary with id
and main-content
just like in the static declaration. Both id
will always be of type string
and main-content
will always be of type object
, and accompanied by a definition of its structure. Within the insurances
array, you must define concrete examples in the __example__
field.
Property | Limit / Restriction |
---|---|
list-items | minimum 1 and maximum 20 items Content will not be rendered if the limit is reached |
label | 80 characters Content will truncate if the limit is reached |
description | 300 characters Content will truncate if the limit is reached |
Content over the limit specified will not be rendered.
Add-on / property | Property | Limit / Restriction |
---|---|---|
start | image | 100KB Images over the limit will be replaced by a placeholder |
main-content | title description metadata | 30 characters 20 characters 80 characters |
end | title description metadata | 10 characters 10 characters 10 characters |
badge | 15 characters | |
tags | 15 characters 3 items |
Here's a corrected version:
If you check the attribute model of certain components (Dropdown
, DatePicker
, RadioGroup
and CheckboxGroup
), you will find that some of them accept the on-xxxx-action
attribute. This attribute allows the component to trigger a data-exchange action. It can be used in the following scenarios:
The following steps require communication between the client and the business server. Please ensure that you have configured the data channel before attempting to use this feature.
Let's begin with a minimal example, consisting of an empty form and a CTA button, and gradually add more components.
So, we want to build a simple form that takes a date and displays the list of available time slots. First, we'll add a DatePicker
component:
Next step is to add a Dropdown
where we will display all available timeslots:
Until now, we've been incorporating static mock data, but now we aim to connect a screen with dynamic data. Dynamic data can originate from various sources:
navigate
- transitioning from the previous screen using a navigate
actiondata_exchange
- a request to the business serverIn this example, we'll assume that the data will come from a data_exchange
request. So, let's instruct Flow JSON to use the data channel request by providing the "data_api_version": "3.0"
property.
Let's provide "on-select-action"
to the DatePicker
component so we can execute the call to the business server. In the payload
, we can pass any data we want to the business server to understand the type of request.
{ "on-select-action":{ "name":"data_exchange", "payload":{ "date":"${form.date}", "component_action":"update_date" } } }
In this example, we'll send the value of the field date
to the action payload, and we'll also add some static data "component_action": "update_date"
to help the server recognize the type of request. There is no strict format here; you can choose whatever works for your case.
Now when you try to select a date, a data_exchange
request will be executed. The server may return the data that can change the UI. For now, our Flow doesn't expect or use any data from the server. Let's fix it by first defining the data model that we expect for a screen.
Let's declare a data
property for the screen outlining the data that we expect to receive from the server. So, we want to receive an available_slots
array with timeslot options.
It should have the following model. The __example__
field is mock data used to display the data within the web preview.
{ "available_slots": { "type": "array", "items": { "type": "object", "properties": { "id": {"type": "string"}, "title": {"type": "string"} } }, "__example__": [ {"id": "1", "title": "08:00"}, {"id": "2", "title": "09:00"} ] } }
It means that the expected payload to be returned from server can look like the following:
{ "version": "3.0", "screen": "BOOKING", "data": { "available_slots": [ {"id": "1", "title": "08:00"}, {"id": "2", "title": "09:00"} ] } }
So you Flow JSON now should look like the following:
Now, when we select a date in DatePicker
, the application will send a request to the business server to get available timeslots. However, we don't want a Dropdown
to be visible until there is data to display. How can we hide it?
For this purpose, we can use the visible
attribute on Dropdown
and connect it with server data. The business server can control the visibility of the component based on a set condition.
So, we need to make the following changes:
is_dropdown_visible
in the data
model of the screen."visible": "${data.is_dropdown_visible}"
.Let's update our code:
NOTE: The current version of the playground doesn't support endpoint requests
That's it! Now you have a dynamic component set up. If you're facing any challenges, feel free to ask a question on the developer forum. We'll be happy to help!