# Multistep Form

Multistep form is a new generation of the [Form](/web-pages/components/legacy-components/form.md) component (for now we keep them both available). It allows users to create complex multistep dynamic forms which are personalised for app users.

### Learning the Basic Component Concepts

* **Form step** (section). A block that includes **Form elements**.
* **Form element**. Could be one of the following:
  * Text paragraph;
  * Inputs (up to 12);
  * Action buttons (up to 12);
  * Submit button;
  * Hint;
  * Sub-header;
  * Redirect.
* **Object model**. JSON-object that includes the current fields' values (default values and filled by the user).
* **Form state**. JSON-object that includes one ore several parameters of the current form state. There are two default properties: `step` defines which form step is displayed now) and `popup` shows the popup and the relevant step in it.

<figure><img src="/files/Y2fRlGMmdrk5icvkD1Te" alt=""><figcaption></figcaption></figure>

### Building a Simple Form

Let's start from creating a simple form where all users (both authorised and unauthorised) would be able to add new book, filling it's title. First of all, we are creating a data structure and then follow the steps.

#### Step 1. Add a Multistep form to your page

<figure><img src="/files/fr98oFpLjLUoQYcBmD3L" alt=""><figcaption></figcaption></figure>

#### Step 2. Configure endpoint&#x20;

We need to have the endpoint for creating/editing  objects. For the beginning we may make it public.

<figure><img src="/files/LRxlUXRllvoXONmIKpkw" alt=""><figcaption><p>Creating new public endpoint</p></figcaption></figure>

#### Step 3.  Add step elements

By default, we have 2 form steps: `default step` and `submitted`. Let's configure them!

<figure><img src="/files/5bM3jg8r3ozUDQJiiUMG" alt=""><figcaption></figcaption></figure>

Add new element to `default step`:

<figure><img src="/files/BrvqIs6M3RQNZ4SNwLpj" alt=""><figcaption></figcaption></figure>

Choose **Inputs** element. Here we can configure inputs for filling fields available for reading (as well as state properties):

<figure><img src="/files/qBWPOjNyaV7e2rsol1nj" alt=""><figcaption></figcaption></figure>

The second element will be "Submit". It'll send the POST request to the endpoint creating new object. Also, submit changes Form state `step` current value → `submitted`

<figure><img src="/files/nbrXsKdVBC0kSyJtl6w0" alt=""><figcaption></figcaption></figure>

#### Step 4.  Set up the first form step

The last thing that we need to configure the default value of the state – define the first step in the Form:

<figure><img src="/files/mRpdIBGljQjelVDRPemy" alt=""><figcaption></figcaption></figure>

#### Step 5.  Test the form!

Push "Save" and – *voilà*:

<figure><img src="/files/Mmc51MzsG6zcCj14GBvz" alt=""><figcaption></figcaption></figure>

### Applying the Templating engine

You can use templating engine in the form title, description, in step elements, etc. The available fields include:

* **Form State** properties
* Fields from **Object model**
* **WebUser**'s fields like `firstName`, `lastName`, `role`, `userpic`, `id`

<div align="left"><figure><img src="/files/MqF5ex26TyB8wp2FRCbH" alt="" width="375"><figcaption><p>Paragraph element allows to insert HTML and to use the Templating engine</p></figcaption></figure></div>

If the element has a description `<HTML /> is allowed here`, you can apply HTML and CSS.

You can use the templating engine in different elements like paragraph, sub-header, input descriptions, etc.

### Navigating between steps

As we pinpointed, the current step is defined by the form state, `FormState.step`.

For example, if you want to start from `my step`, you need to define it as a default value:

#### Setting default step

<figure><img src="/files/2M1jPQKUlQE5GWLhz5P4" alt=""><figcaption></figcaption></figure>

#### Changing state

There are the following ways to change the state (and, the `step` property in particular):

* Add **Inputs** element and define it as an Input for changing the state. You can configure it as a plain text input, as a dropdown select or a button line. For select and button line you need to add  options. Those options can be set manually or pulled from the object's field (type of json, an array of key-value pairs like `[{"key" : "option1", "value" : "option one"}, {"key" : "option2", "value" : "option two"}]`).

<figure><img src="/files/jYpKqrFNOQHTvUiqSgvX" alt=""><figcaption><p>A dropdown for changing the state property — options are set manually here</p></figcaption></figure>

* Apply [Action button](#using-action-buttons) for changing the state;
* Apply [Sync request processing](#processing-requests-synchronically).

#### Steps (sections) visibility

By default the step (section) is visible if its **name** == **FormState.step**. If you want to make it visible in other cases, use Advanced step settings:

<figure><img src="/files/rLrvmD2k8p0iJ0yzrkof" alt=""><figcaption></figcaption></figure>

The step may be visible always or when the FormState.step value is in the list (comma separated)

### Debugging

You can turn on debug for displaying Form Model (and system messages on developer console about [Conditions](#configuring-conditional-visibility-of-elements)) and Form State:

<figure><img src="/files/Qbq3AmU8yBOfHrW4g8YM" alt=""><figcaption></figcaption></figure>

Here is how debug mode looks like:

<figure><img src="/files/TSbPcCBYVGBGKvC3CKIY" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
Don't forget to turn off the debug when you go public with your app!
{% endhint %}

### Setting up Dynamic Inputs

One may need an input that dynamically provides user with options. It may be a dropdown select, radio buttons, tags. etc. The options may depend on the other fields' values, on the user's role, and on other parameters. Let's figure out how to set up the dynamic input!

{% hint style="warning" %}
First and foremost — the dynamic input is one for `link` or `arrayLink` fields. The options are defined by the request to the additional endpoint.
{% endhint %}

Example of a **dynamic input**. first input is a radio button: "guys or girls". The dropdown below provides us with the options according to the first choice:

<figure><img src="/files/1yosXgixX204xrjl0MMg" alt=""><figcaption></figcaption></figure>

There are the following options for rendering dynamic input:

* Dropdown select (for `link`)
* Dropdown multi-select (for `arrayLink`)
* Radio-buttons (for `link`)
* Checkboxes (for `arrayLink`)
* Tags (both for `link` and `arrayLink`)
* Images-radio-buttons (for `link`)
* Images-checkboxes  (for `arrayLink`)

Dropdowns support any number of options thanks to **dynamic filtering**.

#### Configuring endpoint for Dynamic inputs

Any dynamic input requires an endpoint. You can configure filters and sorting in this endpoint as you wish. Moreover, don't forget to set up [structure visible name](/data/data-structures.md#structure-visible-name) and make it available for reading in that endpoint.

<div><figure><img src="/files/0c8xXDW5oD6gsdA8qUPY" alt=""><figcaption></figcaption></figure> <figure><img src="/files/QlitpagAMjyvemb5Iz63" alt=""><figcaption></figcaption></figure></div>

**Important**: if you use dropdown, there have to be system filters for `_value` and `_filer`. if you create an endpoint right from the Multiform component, that filter is added automatically. But pay attention, that if you want filtering (quick search in the dropdown) work with more fields, add them in the filter (`field like _filter`)

<figure><img src="/files/XtaqH7anoYmM2Wlsekvf" alt=""><figcaption></figcaption></figure>

#### Dynamic filtering

If you want to connect filtering on endpoint with the values that user fills, use custom request parameters and pass them those values.

<div><figure><img src="/files/5yvbK0pE65jFUEZuq3RU" alt=""><figcaption></figcaption></figure> <figure><img src="/files/Qew2Q2UiRlzoAozrFBLv" alt=""><figcaption></figcaption></figure></div>

#### Saving options quantity

If you like, you can save the options quantity to a state field. It works for hidden elements as well.

<figure><img src="/files/yQ8VxGup0Nm3njzDDXKJ" alt=""><figcaption></figcaption></figure>

### Configuring Conditional Visibility of Elements

You can set up the conditional visibility for each step element and for each action separately.

<figure><img src="/files/qutw8vieEDsrznlv0hTq" alt=""><figcaption></figcaption></figure>

The conditions can be combined either with `AND` or `OR` operators. You can compare current model fields and state properties with expressions (using the [Templating engine](#applying-the-templating-engine)). There are the following operators for comparison:

* equal, not equal
* contains/dos not contain (for Directual arrays – *comma separated strings*)
* in/not in (for Directual arrays – *comma separated strings*)
* empty/not empty (no second value)
* model is changed/not changed since last submit (no any values at all)

### Using Actions

Action is an element that can do the following:

* Send POST-request to API-endpoint
* Edit object model or state (including resetting the model and discarding changes in it)

Action can be either button or auto-action (performed on a certain step or when a certain field is changed)

One configures an action (tab **Actions**) first and then add it to the form as an element

<div><figure><img src="/files/uEeHdvtKp5z42S9RHvwB" alt=""><figcaption></figcaption></figure> <figure><img src="/files/1UjKcXtQfea7f1fDWf56" alt=""><figcaption></figcaption></figure></div>

There can be a few action buttons within a single form element, in a row.

Each action button has its own visibility conditions, [similar to element ones](#configuring-conditional-visibility-of-elements). One can hide or disable the button conditionally.

Actions support [sync API response processing](#processing-requests-synchronically).

### Submitting the model

To save the whole model to the object you can use **Submit** element

<figure><img src="/files/s29IkI1hPUBdTihezn8e" alt=""><figcaption></figcaption></figure>

By default the submit button resets the model and sets the `FormState.step` to `submitted`.

You can change those settings: keep the model and choose different step.

Also, you can set up conditional visibility. Common case: hide the submit button if the model is not changed.

On the State tab you can turn on saving state to a certain field on submit.

Submit supports [sync API response processing](#processing-requests-synchronically).

### Editing Existing Objects

Turn on switch "Edit the 1-st object in API-response"

<figure><img src="/files/Efk9w9JI79LJ17aeXBwF" alt=""><figcaption></figcaption></figure>

{% hint style="warning" %}
Editing an object pay attention to the following:

* Object's fields including ID have to be available both for reading and writing
* Form takes the first object from the endpoint. Configure filters or sorting accordingly.

Tip: usually endpoint filters depend on [parameters from URL](/web-pages/setting-up-pages-layout/subpages-and-url-parameters.md)
{% endhint %}

If you want to proceed editing object after submitting, turn on "Keep the model" on [Submit element](#submitting-the-model).

### Storing State in the Object

If you **edit an object**, you can restore the state from it. There are two options.

#### 1. Getting state properties from object fields

<figure><img src="/files/l5fqnwceFnbKdbEptYGM" alt=""><figcaption></figcaption></figure>

#### 2. Getting the whole state from a single field type of JSON

<figure><img src="/files/L5eezHEH4TCxgZyoAqKh" alt=""><figcaption></figcaption></figure>

### Using Popups

You can place any Step (section) to the popup:

<figure><img src="/files/wD9iGRgVpY3O9LLK6YIU" alt=""><figcaption></figcaption></figure>

Similar to `step` [configuration](#steps-sections-visibility) you can set up `popup` specifying which section should be displayed in the popup (for example, [using Action button](#using-actions)):

<div><figure><img src="/files/4Gg56TWZpkP3QzWO5mJU" alt=""><figcaption></figcaption></figure> <figure><img src="/files/EW1VDVojl1S3WatAi763" alt=""><figcaption></figcaption></figure></div>

If you like you can even configure a chain of popups!

### Processing Requests Synchronically

{% hint style="warning" %}
This feature turns Multistep-form into a super-powerful component!
{% endhint %}

[Submit](#submitting-the-model) and [Action](#using-actions) can send a POST-request. As we know, the [POST-request can be synchronous](/api-integrations/api-endpoints-security-layer/advanced-techniques-for-get-requesting/synchronic-scenarios-for-post-requests.md). That means the API response may contain the result of the object processing within the scenario.

Use [API-response step](/scenarios/editing-scenarios/integration-steps/api-response.md) in the scenario and compose a response in the following format:

```json
//if you want to edit model:
{
    "object": {
        "field1" : "value",
        ...
    }
}

//if you want to edit form state:
{
    "state": {
        "step" : "value",
        "popup" : null
        ...
    }
}

//if you want to edit both:
{
    "state": {
        "step" : "value",
        "popup" : null
        ...
    },
    "object": {
        "field1" : "value",
        ...
    }
}

// if you want to redirect user, you can do it as well!
{
    "redirect": {
        "target" : "./{{myField}}", // similar to LINK BUTTON component
        "delay" : 500 // in millisectods. 0 – by default
        ...
    }
}

// if you want all dynamic fields refresh their options
{
    "refresh": true
}
```

### Setting up Progress Bar

You can add a progress bar to the form:

<figure><img src="/files/GmQUSlfxD4c29LLRXVod" alt=""><figcaption></figcaption></figure>

First—better to put progress bar in a step that is [visible everywhere](#steps-sections-visibility) (or at leas on the steps that are included into the progress).

Configure the progress bar, adding steps into it, arranging the order, and filling steps' names, descriptions, etc.

<figure><img src="/files/FQnEVz7aMqmgzO8jt7iG" alt=""><figcaption></figcaption></figure>

### Using Redirect Element

**Redirect** element (surprise!) redirects the user. It works like [Link button](/web-pages/components/link-button.md), but automatically.

Bear in mind that you can redirect to the page or a subpage using object fields or form state properties in target URL.

The common case: the form creates the object, [scenario synchronically](#processing-requests-synchronically) returns its ID, and the redirect element leads the user to the page where he proceeds editing the object.

### Online Refreshing with Socket.io

If you [edit an object](#editing-existing-objects) using the Multiform, you can update it using [plugin Socket.io](/plugins/using-plugins/websockets-socket.io.md).

#### Step 1. Configure the form

The updated fields have to be **available for reading**

<figure><img src="/files/MewtIZzkgv12wWCgAjJ6" alt=""><figcaption></figcaption></figure>

The form settings includes "Edit object" option

<figure><img src="/files/YVgKWelg33X1LxNvTMIA" alt=""><figcaption></figcaption></figure>

Here is how the form look like (be sure that your endpoint provides you with the required object. If not — use filters and sorting)

<figure><img src="/files/bJ0iIcs7FtAS3lHpLRHe" alt=""><figcaption><p>Object on the platform (left) and the form (right)</p></figcaption></figure>

#### Step 2. Install Socket plugin and configure it

Install the plugin from the Marketplace

<figure><img src="/files/Kxha2xPOWKJ1qPmRk16e" alt=""><figcaption></figcaption></figure>

Create a scenario, that triggers when object is Changed. It calls the Socket plugin for all users (`*` in the first field), for a certain event (in our example event name = `refresh`)

<div><figure><img src="/files/mlYUKIeave60udPUARmv" alt=""><figcaption><p>Start step</p></figcaption></figure> <figure><img src="/files/86KM2kdl3HfX2bYppY1Y" alt=""><figcaption><p>The whole scenario</p></figcaption></figure> <figure><img src="/files/7Rkblz7EYxBK1MpcSoFm" alt=""><figcaption><p>Socket (push) step</p></figcaption></figure></div>

{% hint style="info" %}
Don't forget to publish and run the scenario!
{% endhint %}

Next — add a refresher component to the page where the form is located (use the same event name. In our case — `refresh`)

<figure><img src="/files/uV3Bhky7ptDZ0UBxo1VO" alt=""><figcaption><p>Web-page with the form and socket refresher</p></figcaption></figure>

That it is! Result:

<figure><img src="/files/kUBXUgx8qIJqgAmrj5ll" alt=""><figcaption></figcaption></figure>

### Using data-actions

You can now make any HTML element inside a Multistep Form interactive using data-action-type attributes. This allows buttons, links, or spans to trigger actions, navigate, or open modals — directly from HTML content (e.g. inside **Paragraph** element).

#### Supported types

| Type   | Description                                | Example                                                                             |
| ------ | ------------------------------------------ | ----------------------------------------------------------------------------------- |
| action | Run an action defined in the form settings | `<button data-action-type="action" data-action-data="like_action">👍 Like</button>` |
| route  | Navigate to a page (supports templating)   | `<a data-action-type="route" data-action-data="/profile/{{id}}">View Profile</a>`   |
| modal  | Open a modal window                        | `<span data-action-type="modal" data-action-data="/edit/{{id}}">✏️ Edit</span>`     |

#### Key points

* Templating support – use {{field}} in data-action-data.
* Action integration – call existing actions by name or ID.
* Event delegation – works seamlessly with other click handlers.
* Compatible with ElementText and any HTML-enabled content.

#### Example

```html
<!-- Execute an action -->
<button data-action-type="action" 
        data-action-data="like_action">
    👍 Like
</button>

<!-- Navigate to a page -->
<a data-action-type="route" 
   data-action-data="/profile/{{id}}">
    View Profile
</a>

<!-- Open modal -->
<span data-action-type="modal" 
      data-action-data="/edit/{{id}}">
    ✏️ Edit
</span>
```

This feature lets you build rich, interactive forms without extra JavaScript — just simple HTML attributes.

### Using Custom API

Multistep Form provides a public API for programmatic form control from external JavaScript code. This allows you to integrate the form with custom logic and dynamically modify form data and state.

[Explore custom API](/web-pages/components/multistep-form/multiform-custom-api.md)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://readme.directual.com/web-pages/components/multistep-form.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
