Skip to main content

Multiple Input Group

An Array type defines a repeatable set of fields.
It allows users to fill in the same sub-form multiple times, producing an array of objects in the output data.

This is typically used when you need to collect several entries that share the same structure — for example, a list of members, vehicles, or addresses.

Each iteration represents one complete instance of the defined structure.
Users can add or remove items dynamically through the interface.

  • The internal components behave like standard form fields (supporting validations, visibility, and conditions).
  • Each array item is independent — changes in one item do not affect others.
  • The way the array is rendered (arrayType) can vary (e.g. as a table or list) depending on the configuration.
  • When the array is empty, the empty_label text is displayed if defined.

Example

{
"member_list": {
"type": "array",
"label": "",
"arrayType": "table",
"array_actions": {
"max": 2,
"add_label": "Add member",
"title": "Member",
"remove_label": "Remove member",
"empty_label": "No member",
"actions_title": "Remove"
},
"properties": {
"name": {
"label": "Name",
"component": "text"
},
"did_agree": {
"label": "Did agree",
"component": "true_false"
},
"accept_terms": {
"label": "Accept terms",
"component": "checkbox"
},
"date_of_birth": {
"label": "Date of birth",
"component": "date"
}
}
}
}

This configuration defines a repeatable list of members.
The user can add up to two members, each represented as a row in a table layout.


Output structure

The resulting value is an array of objects.
Each element corresponds to one filled instance of the defined properties.

Example output:

[
{
"name": "Alice",
"did_agree": true,
"accept_terms": true,
"date_of_birth": "1992-03-15"
},
{
"name": "Bob",
"did_agree": false,
"accept_terms": false,
"date_of_birth": "1988-07-02"
}
]

Supported keys

KeyRequiredDescription
typeMust be set to array.
labelDisplay label shown above the group.
arrayTypeDefines how the list is visually displayed (table, list, block, etc.).
array_actionsObject controlling add/remove behavior, labels, and item limits.
propertiesDefinition of the repeated fields (same structure as a group).
defaultInitial array of objects to pre-fill the list.
visibleBoolean or array of conditions controlling visibility.
readOnlyDisables add/remove actions and editing of existing items.

array_actions object

The array_actions key defines how the user interacts with the array — adding, removing, or viewing items.
It also allows you to control item limits and customize button labels.

Example

"array_actions": {
"max": 3,
"min": 1,
"add_label": "Add member",
"remove_label": "Remove",
"empty_label": "No member available",
"title": "Member",
"actions_title": "Actions"
}

Supported keys

KeyRequiredTypeDescription
maxnumberMaximum number of items allowed. If reached, the "Add" button is disabled.
minnumberMinimum number of items required.
add_labelstringText shown on the "Add" button.
remove_labelstringText shown on the "Remove" button for each item.
empty_labelstringMessage displayed when the array is empty.
titlestringTitle shown above each item (useful for list or block displays).
actions_titlestringHeader label for the actions column (mainly used in table mode).
addbooleanDefault: true, enable add item
removebooleanDefault: true, enable remove item
info

min and max can be object with a from path, that way the minimum and / or the maximum iteration of the table can be controlled by the data

{
"min": {
"from": "minimum_defined_in_the_data"
}
}
tip

Setting false to array_actions is a shortcut that acts like setting add and remove to false. No actions will be shown


Behavior

  • Each new item is initialized based on the properties definition.
  • Default values defined inside properties are applied when creating a new item.
  • Items can be added or removed dynamically.
  • max and min settings in array_actions define the item limits.
  • Visibility and read-only states apply to the entire array component.
info

To handle conditions based on the current item see the related documentation here

tip

A onValueChange can be applied to each iteations of the components see related documentation here


Count

or tracking and integration purposes, a special __count data property is automatically maintained for each multiple input group. This property keeps track of the current number of items in the array and is updated whenever an item is added or removed.

This allows you to reference the count of entries dynamically elsewhere in the schema or logic conditions.


Example

{
"car_list": {
"type": "array",
"label": "",
"arrayType": "table",
"array_actions": {
"add_label": "Ajouter un article",
"title": "Articles",
"remove_label": "Supprimer",
"empty_label": "Pas d'articles",
"showRowId": true
},
"properties": {
"plate": {
"component": "text",
"label": "Plate"
}
}
}
}

When the form is filled, an internal data key is generated alongside the array value:

{
"car_list": [{ "plate": "ABC123" }, { "plate": "XYZ789" }],
"car_list__count": 2
}

Behavior

  • The __count property is automatically updated whenever:
  • A new row is added.
  • An existing row is removed.
  • The count reflects the current number of visible items in the array.
  • This property can be used in conditions, calculations, or as a reference in other components.
note
  • The count key is always appended to the array’s root key name using a double underscore ().
  • It is a read-only internal value — users cannot modify it manually.
  • This mechanism is useful for data interpolation or validation scenarios that depend on the number of entries.

Disabled

A disabled (see related doc) attribute can be defined on a multiple input group to make all of its fields non-editable.
When the component is disabled, every field inside its properties automatically inherits this state.

{
"member_list": {
"type": "array",
"arrayType": "table",
"disabled": true,
"properties": {
"name": {
"label": "Name",
"component": "text"
},
"age": {
"label": "Age",
"component": "number"
}
}
}
}

In this configuration, the entire table and all its inputs are disabled.

tip

While it is possible to define disabled properties individually on each subfield, it is usually clearer and more maintainable to apply it directly at the component level.


Advanced : Data interpolation within table rows

It is possible to dynamically reference data within the same iteration.
This allows one field to depend on the value of another field from the same row — for example, to populate a select list based on another selected value.

This feature uses data interpolation through variable paths with iteration indexing.


Example

{
"car_list": {
"type": "array",
"label": "",
"arrayType": "table",
"array_actions": {
"title": "Cars"
},
"properties": {
"kind": {
"label": "Kind",
"component": "select",
"list": [
{ "value": "kind_a", "label": "Kind A" },
{ "value": "kind_b", "label": "Kind B" }
]
},
"usage": {
"label": "Usage list depending on kind",
"component": "select",
"list": {
"from": "usage_list.${car_list[x].kind}"
}
}
}
}
}

Explanation

In this configuration:

  • The car_list table defines multiple cars.
  • Each row (iteration) contains two fields: kind and usage.
  • The usage select list depends on the current row’s kind value.

The key expression here is:

"from": "usage_list.${car_list[x].kind}"
  • ${car_list[x].kind} dynamically refers to the kind value of the current row (x represents the current iteration index).
  • The system resolves this expression for each row individually, ensuring that the usage list is context-aware.

Behavior

  • The expression is evaluated separately for each item of the array.
  • Any change in the controlling field (here, kind) triggers an update of the dependent field (here, usage).
  • You can interpolate any property within the same array iteration using the same ${car_list[x].property} syntax.

Filters

There is a way to filter data that will be shown onto the table.

We can define it by setting the filters proprety to the table. It accepts an array of filters. The objective of the filter is to define an array of conditiions that will filter the data of the table. Only the matching items will be shown.

tip

Filtering does not mean that excluded items will be destroyed, they are just not shown in the table


Example

{
"car_list": {
"type": "array",
"label": "",
"arrayType": "table",
"array_actions": {
"title": "Cars"
},
"filters": [
{
"property": {
"from": "car_list[x].kind"
},
"assertion": "equal",
"value": "compact"
}
],
"properties": {
"warning_color": {
"label": "Warning color",
"component": "true_false"
},
"plate": {
"label": "Plate",
"component": "text"
},
"kind": {
"label": "Kind",
"component": "text"
},
"price": {
"label": "Price",
"format": "price",
"type": "text",
"text": {
"from": "car_list[x].price"
},
"color": {
"color": "warning",
"conditions": [
{
"property": "car_list[x].warning_color",
"assertion": "isTrue"
}
]
}
}
}
}
}

In this example each item of the car_list will pass the filter condition and only the one with the property kind equal to compact will be shown.


Validations

Validations can be set to the whole type: array object.

{
"vehicle_list": {
"type": "array",
"label": "",
"arrayType": "table",
"array_actions": {
"title": "Vehicle"
},
"validations": ["required"],
"properties": {
"plate": {
"label": "Plate",
"component": "text"
},
"effective_date": {
"label": "Effective date",
"component": "date"
}
}
}
}

That way we can force the table to be competed.

If you have to make a validation of an item property based on an other property of this item, you can do this by pointing to the item index using [x]

{
"content": {
"type": "array",
"label": "",
"arrayType": "table",
"array_actions": {
"max": 10,
"add_label": "t:add_object",
"title": "t:object_title",
"remove_label": "t:remove_object",
"empty_label": "t:no_object"
},
"properties": {
"content": {
"label": "t:object_type",
"validations": ["required"],
"component": "select",
"list": {
"from": "constants.object_type_list"
}
},
"insured_amount": {
"label": "t:insured_amount",
"component": "price",
"validations": [
"required",
{
"assertion": "isBelow",
"value": {
"from": "content[x].content_selected_list_item.max_insured_amount"
},
"message": "t:trop"
}
]
}
}
}
}