Form Builder Documentation

This page describes how to use the form builder to build custom forms.

How to use the form builder

The easiest approach is to copy an existing form template and use it as a starting point for your own form.

Start by making minor changes in the JSON and click "Refresh to preview" to verify them. Refreshing the preview will update the JSON as well, ensuring consistent and uniform definitions of various field attributes along with default property values.

Labels and names

The label property is a human-readable label of the field, whereas name is a snake_case machine name of the field.

When you click "Refresh to preview", the backend will automatically update name property values to the full name of the field. For example, if you have a group some_group which contains a field named full_name, the field's name will become some_group.full_name. This allows unique identification of a field in a form.

Basic form structure

Each form configuration template is a basic JSON structure that looks like this:

{
  "type": "form",
  "name": "form",
  "label": "User-facing form name",
  "elements": [
    {
      "type": "group",
      "name": "some_group",
      "elements": []
    },
    {
      "type": "group",
      "name": "another_group",
      "elements": []
    }
  ]
}
Important: Each form must have a single top-level element of type form. It must be the first element of the form.

Its direct children must be elements of type group. Children of groups can be of any type except form and group (i.e. nesting of forms and groups/sections is not allowed).

Field types

You can use the following field types in your forms.

Form field

{
  "type": "form",
  "name": "form",
  "label": "User-facing form name"
}

Text field

{
  "type": "text",
  "name": "full_name",
  "label": "Full name"
}

Textarea field

{
  "type": "textarea",
  "name": "comment",
  "label": "Comment"
}

Email field

{
  "type": "email",
  "name": "email",
  "label": "Email address"
}

Choice/radio field

Fields of type choice can show one or more choice options.

{
  "type": "choice",
  "name": "country",
  "label": "Country",
  "params": {
    "multiple": true,
    "options": [
      {
        "label": "Norway",
        "value": "1",
        "help": "Optional help text"
      },
      {
        "label": "Finland",
        "value": "2"
      },
      {
        "label": "Denmark",
        "value": "3"
      }
    ]
  }
}

Set multiple to true for a field with multiple checkboxes. Setting it to false will show radio buttons.

Selector field

Selector fields are similar to choice fields, but they use a dropdown menu to show the available options.

{
  "type": "selector",
  "name": "country",
  "label": "Country",
  "params": {
    "options": [
      {
        "label": "Norway",
        "value": "1",
        "help": "Optional help text"
      },
      {
        "label": "Finland",
        "value": "2"
      },
      {
        "label": "Denmark",
        "value": "3"
      }
    ]
  }
}

Checkbox field

A checkbox field is just a version of a choice field with multiple set to true and only a single choice option.

{
  "type": "choice",
  "name": "terms",
  "params": {
    "multiple": true,
    "options": [
      {
        "label": "I accept the terms and conditions",
        "value": "1"
      }
    ]
  }
}

Toggle field

A toggle field is similar to a checkbox field, but it is rendered as a toggle switch instead of a checkbox and must contain exactly two choice options.

{
  "type": "toggle",
  "name": "toggle",
  "label": "Import company data",
  "params": {
    "options": [
      {
        "label": "false",
        "value": "0"
      },
      {
        "label": "true",
        "value": "1"
      }
    ]
  }
}

Date field

{
  "type": "date",
  "name": "birth_date",
  "label": "Date of birth"
}

Label field

Used to display a formatted label. This field does not accept any user input and is used only for presentation purposes.

{
  "type": "label",
  "name": "birth_date_label",
  "label": "Birth date"
}

Rich text field

Used to render custom HTML markup. This field does not accept any user input and is used only for presentation purposes.

{
  "type": "rich_text",
  "name": "company_intro",
  "value": "<p>We are happy to have you onboard.</p>"
}

Repeater field

A repeater field is a collection of items each of which contains a set of fields specified by the repeater template. The user can add and remove items dynamically.

{
  "name": "employees",
  "type": "repeater",
  "params": {
    "template": {
      "name": "employee",
      "type": "group",
      "elements": [
        {
          "name": "full_name",
          "label": "Full name",
          "type": "text"
        },
        {
          "name": "email",
          "label": "Email address",
          "type": "email"
        }
      ]
    }
  }
}
Note: The template property must contain a single group field which defines the fields that will be included in each item of the repeater.

Field properties

Required

The following properties are required for all field definitions.

  • type - The type of the field. See the list of supported field types above.
  • name - The unique name of the field. Must follow the snake_case naming convention.

Optional

The following properties can be added to any field definition.

  • label - The label text for the field. Use null to hide the label. Default: null
  • help - Optional help text to display below the field. Default: null
  • validators - An array of validator definitions to apply to the field. Default: []
  • params - An object containing additional parameters for the field. The available parameters depend on the field type. Default: []
  • value - Not configurable in the form editor. Default: ''

Customizing field layout

You can customize how many columns are rendered inside a field group, assign fields to specific columns, and make fields span multiple columns. For example:

{
  "type": "group",
  "name": "some_section",
  "label": "Some section",
  "params": {
    "columns": 3
  },
  "elements": [
    {
      "type": "text",
      "name": "full_name",
      "label": "Full name",
      "params": {
        "column": 1
      }
    },
    {
      "type": "email",
      "name": "email",
      "label": "Email",
      "params": {
        "column": 2,
        "columnSpan": 2
      }
    }
  ]
}

Parameters:

  • columns (optional): Specifies the number of columns in a group (up to 3 columns are allowed). Only applies to group fields. Default: 1
  • column (optional): Specifies the column in which the field must be placed in. Default: 1
  • columnSpan (optional): Specifies the number of columns the field should span (i.e. the column "width"). Default: 1

Validators

Validators are used to enforce rules and constraints on form fields. Each validator has a name and optional params object containing configuration options. Validators are applied to fields using the validations array.

Basic Structure

All validators follow this structure:

{
  "name": "ValidatorName",
  "params": {
    "option1": "value1",
    "option2": "value2"
  }
}

Available Validators

NotBlank

Ensures the field is not empty or blank (i.e. makes the field required).

{
  "name": "NotBlank"
}

Blank

Ensures the field is empty or blank.

{
  "name": "Blank"
}

Email

Validates that the field contains a valid email address.

{
  "name": "Email"
}

Length

Validates the length of a text field.

Examples:

{
  "name": "Length",
  "params": {
    "min": 4,
    "max": 20
  }
}
{
  "name": "Length",
  "params": {
    "exactly": 8
  }
}

Parameters:

  • min (optional): Minimum number of characters
  • max (optional): Maximum number of characters
  • exactly (optional): Exact number of characters required
Note: At least one of min, max, or exactly must be specified.

Range

Validates that a numeric value falls within a specified range.

{
  "name": "Range",
  "params": {
    "min": 20,
    "max": 30
  }
}

Parameters:

  • min (optional): Minimum allowed value
  • max (optional): Maximum allowed value
Note: At least one of min or max must be specified.

EqualTo

Validates that the field value equals a specific value.

{
  "name": "EqualTo",
  "params": {
    "value": "expected_value"
  }
}

Parameters:

  • value (required): The expected value to match against

IsTrue

Validates that the field value is either boolean true, integer 1 or string '1'.

{
  "name": "IsTrue"
}

IsFalse

Validates that the field value is either boolean false, integer 0, or string '0'.

{
  "name": "IsFalse"
}

Count

Validates the number of items in a collection (used with repeater fields).

{
  "name": "Count",
  "params": {
    "min": 2,
    "max": 5
  }
}

Parameters:

  • min (optional): Minimum number of items required
  • max (optional): Maximum number of items allowed
  • exactly (optional): Exact number of items required
Note: At least one of min, max, or exactly must be specified.

File

Validates file uploads.

{
  "name": "File",
  "params": {
    "maxSize": 1048576,
    "extensions": "jpg,png,pdf"
  }
}

Parameters:

  • maxSize (optional): Maximum file size in bytes
  • extensions (optional): Comma-separated list of allowed file extensions

Contains

Validates that the field value is one of the allowed values.

{
  "name": "Contains",
  "params": {
    "allowedValues": ["option1", "option2", "option3"]
  }
}

Parameters:

  • allowedValues (required): Array of allowed values

When

Conditionally applies validations based on other field values.

{
  "name": "When",
  "params": {
    "propertyPath": "some.other.field_name",
    "conditions": [
      {
        "name": "EqualTo",
        "params": {
          "value": "expected_value"
        }
      }
    ],
    "validations": [
      {
        "name": "NotBlank"
      }
    ]
  }
}

In the example above, the current field will become required if the value of some.other.field_name is expected_value.

Parameters:

  • propertyPath (required): Absolute path to the field that must pass conditions
  • conditions (required): Array of conditions to check against the field specified in propertyPath
  • validations (required): Array of validators to apply to the current field when conditions are met

Visible

Controls field visibility based on other field values.

{
  "name": "Visible",
  "params": {
    "propertyPath": "some.other.field_name",
    "conditions": [
      {
        "name": "EqualTo",
        "params": {
          "value": 2
        }
      }
    ]
  }
}

Parameters:

  • propertyPath (required): Path to the field that determines visibility
  • conditions (required): Array of conditions to check against the field specified in propertyPath

In the example above, the current field will become visible only if the value of some.other.field_name is 2.

Using Multiple Validators

You can apply multiple validators to a single field by adding them to the validations array:

{
  "name": "email",
  "type": "email",
  "label": "Email Address",
  "validations": [
    {
      "name": "NotBlank"
    },
    {
      "name": "Email"
    },
    {
      "name": "Length",
      "params": {
        "max": 255
      }
    }
  ]
}

Examples

You can find example snippets for common use cases below.

Form section introduction text

Use this snippet as a starting point for adding an introduction text at the top of the form.

{
  "name": "customer_portal_intro",
  "type": "group",
  "params": {
    "columns": 3
  },
  "elements": [
    {
      "name": "customer_portal_intro.label",
      "label": "Customer portal",
      "type": "label"
    },
    {
      "name": "customer_portal_intro.description",
      "type": "rich_text",
      "value": "Some long description text",
      "params": {
        "columnSpan": 2
      }
    }
  ]
}

User repeater

This snippet displays a user repeater where at least one item is required.

{
  "name": "user_section",
  "type": "group",
  "params": {
    "columns": 3
  },
  "elements": [
    {
      "name": "users",
      "type": "repeater",
      "params": {
        "template": {
          "type": "group",
          "name": "user",
          "elements": [
            {
              "type": "text",
              "name": "full_name",
              "label": "Full name",
              "params": {"column": 1},
              "validations": [{"name": "NotBlank"}]
            },
            {
              "type": "email",
              "name": "email",
              "label": "Email",
              "params": {"column": 2},
              "validations": [{"name": "NotBlank"}, {"name": "Email"}]
            },
            {
              "type": "choice",
              "name": "access_type",
              "label": "Access type",
              "params": {
                "column": 3,
                "options": [
                  {"value": "payroll", "label": "Payroll"},
                  {"value": "accounting", "label": "Accounting"},
                  {"value": "payroll_accounting", "label": "Payroll + Accounting", "help": "Includes both payroll and accounting access permissions"}
                ],
                "multiple": false
              },
              "validations": [{"name": "NotBlank"}]
            }
          ]
        }
      },
      "validations": [{"name": "NotBlank"}]
    }
  ]
}