Some checks failed
Server CI / Postgres (shard 0) (push) Has been skipped
Server CI / Postgres (shard 3) (push) Has been skipped
BuildEnv Docker Image / build-image (push) Failing after 4s
BuildEnv Docker Image / build-image-fips (push) Failing after 4s
Migration Review & Release Notes / Generate migration review & release notes (push) Failing after 3s
Server CI / Build Environment (push) Failing after 3s
Server CI / Postgres (shard 1) (push) Has been skipped
Tools CI / check-style (mattermost-govet) (push) Failing after 4s
Server CI / Postgres (shard 2) (push) Has been skipped
Tools CI / check-style (mmgotool) (push) Failing after 3s
Server CI / Elasticsearch v8 Compatibility (push) Has been skipped
Server CI / OpenSearch v2 Compatibility (push) Has been skipped
Server CI / Postgres FIPS (shard 0) (push) Has been skipped
Tools CI / Test (mattermost-govet) (push) Failing after 3s
Server CI / Postgres FIPS (shard 1) (push) Has been skipped
Server CI / Postgres FIPS (shard 2) (push) Has been skipped
Tools CI / Test (mmgotool) (push) Failing after 3s
Server CI / Postgres FIPS (shard 3) (push) Has been skipped
Server CI / Run mmctl tests (push) Has been skipped
Server CI / Run mmctl tests (FIPS) (push) Has been skipped
Server CI / Merge Postgres Test Results (push) Has been skipped
Server CI / Merge Postgres FIPS Test Results (push) Has been skipped
Server CI / Check backport migrations (push) Has been skipped
Server CI / Check generated files (push) Has been skipped
Server CI / check-style (push) Has been skipped
Server CI / Vet API (push) Has been skipped
Server CI / Build mattermost server app (push) Has been skipped
Server CI / Server CI Complete (push) Failing after 2s
Server CI / Server CI Artifacts (push) Has been skipped
Server CI / Sentry Upload (push) Has been skipped
Server CI / Server CI Report (push) Failing after 5m1s
Server CI Nightly Race / Race Detector (push) Has been skipped
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
Webapp CI Cache Warm / Warm Webapp node_modules Cache (push) Has been cancelled
E2E CI Cache Warm / Warm E2E npm Registry Cache (push) Has been cancelled
API / build (push) Has been cancelled
Web App CI / check-types (push) Has been cancelled
Web App CI / check-lint (push) Has been cancelled
Web App CI / check-i18n (push) Has been cancelled
Web App CI / check-external-links (push) Has been cancelled
Web App CI / test (platform) (push) Has been cancelled
Web App CI / test (mattermost-redux) (push) Has been cancelled
Web App CI / test (channels shard 1/4) (push) Has been cancelled
Web App CI / test (channels shard 2/4) (push) Has been cancelled
Web App CI / test (channels shard 3/4) (push) Has been cancelled
Web App CI / test (channels shard 4/4) (push) Has been cancelled
Web App CI / upload-coverage (push) Has been cancelled
Web App CI / build (push) Has been cancelled
YAML Lint / yamllint (push) Has been cancelled
Push mirrored docker images / cd/Push mirrored docker images (push) Has been cancelled
docs-cd / Build and deploy docs (push) Has been cancelled
Docs CI / build (push) Has been cancelled
E2E Cache Warm: Cypress deps / Warm Cypress deps cache (push) Has been cancelled
Scorecards supply-chain security / Scorecard analysis (push) Has been cancelled
Server CI Weekly / Postgres FIPS (push) Has been skipped
Server CI Weekly / Run mmctl tests (FIPS) (push) Has been skipped
Server CI Weekly / Postgres with binary parameters (push) Has been skipped
Server CI Weekly / Build Environment (push) Failing after 1s
Server CI Cache Warm / Warm Go Module and Build Cache (push) Failing after 2s
Server CI Nightly Race / Build Environment (push) Failing after 1s
1213 lines
60 KiB
Markdown
1213 lines
60 KiB
Markdown
---
|
||
title: "Use interactive dialogs"
|
||
description: "Interactive dialogs let applications gather structured input from Mattermost users and submit it back to an integration through single-step forms or multi-step workflows."
|
||
sidebar_label: "Interactive dialogs"
|
||
sidebar_position: 70
|
||
---
|
||
|
||
Integrations open dialogs by sending an `HTTP POST`, containing some data in the request body, to an endpoint on the Mattermost server. Integrations can use this endpoint to open dialogs when users [click message buttons or select an option from a menu](/developers/integrate/plugins/interactive-messages), or use a
|
||
[custom slash command](/developers/integrate/slash-commands).
|
||
|
||
Moreover, [plugins](/developers/integrate/plugins/using-and-managing-plugins) can trigger a dialog based on user actions. For instance, if a plugin adds a button in the channel header, clicking that button may open a dialog.
|
||
|
||
From Mattermost v11.10, dialogs can be stacked: an [`action_button`](#action-button-elements) element inside a dialog lets a user open a child dialog on top of the current one. Up to three dialogs may be open at once; any request to open a dialog beyond this limit is silently ignored by the client.
|
||
|
||
Here is an example of what a dialog looks like for creating a Jira issue within the Mattermost user interface:
|
||
|
||

|
||
|
||
## Open a dialog
|
||
|
||
To open a dialog, your integration must first receive an HTTP request from the Mattermost server. This request will be triggered by a slash command or an interactive message. It will include a trigger ID.
|
||
|
||
Once you have the trigger ID you can use it to open the interactive dialog by sending an `HTTP POST` request to `https://<your-mattermost-url>/api/v4/actions/dialogs/open`. See the below section for what to include in the body of that HTTP request.
|
||
|
||
## Parameters
|
||
|
||
Interactive dialogs support the following parameters:
|
||
|
||
| Parameter | Type | Description |
|
||
|---------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||
| `title` | String | Title of the dialog. Maximum 24 characters. |
|
||
| `introduction_text` | String | Markdown-formatted introduction text which is displayed above the dialog `elements`. |
|
||
| `elements` | Array | See below for more details on elements. If none are supplied the dialog box acts as a simple confirmation. |
|
||
| `url` | String | The URL to send the submitted dialog payload to. |
|
||
| `icon_url` | String | (Optional) The URL of the icon used for your dialog. If none specified, no icon is displayed. |
|
||
| `submit_label` | String | (Optional) Label of the button to complete the dialog. Default is `Submit`. |
|
||
| `notify_on_cancel` | Boolean | (Optional) When `true`, sends an event back to the integration whenever there's a user-induced dialog cancellation. No other data is sent back with the event. Default is `false`. |
|
||
| `state` | String | (Optional) String provided by the integration that will be echoed back with dialog submission. Default is the empty string. |
|
||
| `source_url` | String | (Optional) URL for field refresh requests. When a select element with `refresh: true` changes value, Mattermost sends a refresh request to this URL. Also used as the endpoint for multi-step form responses. |
|
||
|
||
Sample JSON is given below. Form submissions are sent back to the URL defined by the integration. You must also include the trigger ID you received from the slash command or interactive message.
|
||
|
||
```json
|
||
{
|
||
"trigger_id": "<unique ID generated by the server>",
|
||
"url": "<URL to send the submitted request to>",
|
||
"dialog": {
|
||
"callback_id": "<ID specified by the integration to identify the request>",
|
||
"title": "<title of the dialog>",
|
||
"introduction_text": "<Text describing the dialog box content>",
|
||
"elements": ["<Array of UI elements to display in the dialog>"],
|
||
"submit_label": "<label of the button to complete the dialog>",
|
||
"notify_on_cancel": false,
|
||
"state": "<string provided by the integration that will be echoed back with dialog submission>",
|
||
"source_url": "<optional URL for field refresh and multi-step form handling>"
|
||
}
|
||
}
|
||
```
|
||
|
||
## Elements
|
||
|
||
Each dialog supports elements for users to enter information.
|
||
|
||
- `text`: Single-line plain text field. Use this for inputs such as names, email addresses, or phone numbers.
|
||
- `textarea`: Multi-line plain text field. Use this field when the answer is expected to be longer than 150 characters.
|
||
- `select`: Message menu. Use this for pre-selected choices. Can either be static menus or dynamic menus generated from users and Public channels of the system. For more information on message menus, see [the documentation](/developers/integrate/plugins/interactive-messages).
|
||
- `bool`: Checkbox option. Use this for binary selection.
|
||
- `radio`: Radio button option. Use this to quickly select an option from pre-selected choices.
|
||
- `date`: Date picker field. Use this for selecting dates without time information.
|
||
- `datetime`: Date and time picker field. Use this for selecting both date and time with timezone support.
|
||
- `file`: File upload field. Use this to allow users to attach one or more files as part of a dialog submission.
|
||
- `action_button`: Clickable button that opens a child (stacked) dialog. Use this to branch into a follow-up dialog without submitting the current one. (Minimum server version 11.10.)
|
||
|
||
Each element is required by default, otherwise the client will return an error as shown below. Note that the error message will appear below the help text, if one is specified. To make an element optional, set the field `"optional": "true"`.
|
||
|
||

|
||
|
||
### Text elements
|
||
|
||
Text elements are single-line plain text fields. Below is an example of a `text` element that asks for an email address.
|
||
|
||

|
||
|
||
```json
|
||
{
|
||
"display_name": "Email",
|
||
"name": "email",
|
||
"type": "text",
|
||
"subtype": "email",
|
||
"placeholder": "placeholder@example.com"
|
||
}
|
||
```
|
||
|
||
There is an optional `"subtype": "email"` field in the above example, which specifies the keyboard layout used on mobile. For this example, the email keypad is shown to the user given the subtype is set to `email`.
|
||
|
||
The full list of supported fields is included below:
|
||
|
||
| Field | Type | Description |
|
||
|----------------|---------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||
| `display_name` | String | Display name of the field shown to the user in the dialog. Maximum 24 characters. |
|
||
| `name` | String | Name of the field element used by the integration. Maximum 300 characters. You should use unique `name` fields in the same dialog. |
|
||
| `type` | String | Set this value to `text` for a text element. |
|
||
| `subtype` | String | (Optional) One of `text`, `email`, `number`, `password` (as of v5.14), `tel`, or `url`. Default is `text`. Use this to set which keypad is presented to users on mobile when entering the field. |
|
||
| `min_length` | Integer | (Optional) Minimum input length allowed for an element. Default is 0. |
|
||
| `max_length` | Integer | (Optional) Maximum input length allowed for an element. Default is 150. If you expect the input to be greater 150 characters, consider using a `textarea` type element instead. |
|
||
| `optional` | Boolean | (Optional) Set to `true` if this form element is not required. Default is `false`. |
|
||
| `help_text` | String | (Optional) Set help text for this form element. Maximum 150 characters. |
|
||
| `default` | String | (Optional) Set a default value for this form element. Maximum 150 characters. |
|
||
| `placeholder` | String | (Optional) A string displayed to help guide users in completing the element. Maximum 150 characters. |
|
||
|
||
### Textarea elements
|
||
|
||
Textarea elements are multi-line plain text fields. A sample JSON is provided below:
|
||
|
||
```json
|
||
{
|
||
"display_name": "Ticket Description",
|
||
"name": "ticket_description",
|
||
"type": "textarea",
|
||
"help_text": "Provide description for your ticket."
|
||
}
|
||
```
|
||
|
||
The maximum length for a `textarea` is 3,000 characters.
|
||
|
||
The list of supported fields is the same as for the `textarea` type element.
|
||
|
||
|
||
| Field | Type | Description |
|
||
|----------------|---------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||
| `display_name` | String | Display name of the field shown to the user in the dialog. Maximum 24 characters. |
|
||
| `name` | String | Name of the field element used by the integration. Maximum 300 characters. You should use unique `name` fields in the same dialog. |
|
||
| `type` | String | Set this value to `texareat` for a textarea element. |
|
||
| `subtype` | String | (Optional) One of `text`, `email`, `number`, `password` (as of v5.14), `tel`, or `url`. Default is `text`. Use this to set which keypad is presented to users on mobile when entering the field. |
|
||
| `min_length` | Integer | (Optional) Minimum input length allowed for an element. Default is 0. |
|
||
| `max_length` | Integer | (Optional) Maximum input length allowed for an element. Default is 3000. |
|
||
| `optional` | Boolean | (Optional) Set to `true` if this form element is not required. Default is `false`. |
|
||
| `help_text` | String | (Optional) Set help text for this form element. Maximum 150 characters. |
|
||
| `default` | String | (Optional) Set a default value for this form element. Maximum 3000 characters. |
|
||
| `placeholder` | String | (Optional) A string displayed to help guide users in completing the element. Maximum 3000 characters. |
|
||
|
||
### Select elements
|
||
|
||
Select elements are message menus that allow users to select one or multiple predefined options from a list. Below is an example of a `select` element that asks for one of three different options.
|
||
|
||

|
||
|
||

|
||
|
||
```json
|
||
{
|
||
"display_name": "Option Selector",
|
||
"name": "options",
|
||
"type": "select",
|
||
"options": [
|
||
{
|
||
"text": "Option1",
|
||
"value": "opt1"
|
||
},
|
||
{
|
||
"text": "Option2",
|
||
"value": "opt2"
|
||
},
|
||
{
|
||
"text": "Option3",
|
||
"value": "opt3"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
#### Multiselect support
|
||
##### Minimum Server Version: 11.0
|
||
|
||
Select elements can be configured to allow multiple selections by setting the `multiselect` parameter to `true`. When multiselect is enabled, users can choose multiple options from the list.
|
||
|
||
```json
|
||
{
|
||
"display_name": "Multiple Options",
|
||
"name": "multi_options",
|
||
"type": "select",
|
||
"multiselect": true,
|
||
"default": "opt1,opt3",
|
||
"options": [
|
||
{
|
||
"text": "Option1",
|
||
"value": "opt1"
|
||
},
|
||
{
|
||
"text": "Option2",
|
||
"value": "opt2"
|
||
},
|
||
{
|
||
"text": "Option3",
|
||
"value": "opt3"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
For multiselect elements, default values can be specified as a comma-separated string (e.g., `"opt1,opt3"` to pre-select Option1 and Option3).
|
||
|
||
#### Dynamic select support
|
||
##### Minimum Server Version: 11.0
|
||
|
||
Select elements can be configured to load options dynamically from an external API endpoint. This enables real-time filtering, searching, and loading of options based on user input.
|
||
|
||
To use dynamic select, set `data_source: "dynamic"` and provide a `data_source_url` that points to your lookup endpoint:
|
||
|
||
```json
|
||
{
|
||
"display_name": "Dynamic Options",
|
||
"name": "dynamic_field",
|
||
"type": "select",
|
||
"data_source": "dynamic",
|
||
"data_source_url": "https://your-mattermost-server.com/plugins/your-plugin-id/api/lookup",
|
||
"placeholder": "Search for options..."
|
||
}
|
||
```
|
||
|
||
When users interact with a dynamic select field, Mattermost sends an HTTP POST request to the `/api/v4/actions/dialogs/lookup` endpoint, which proxies the request to your `data_source_url`. The payload uses the same `SubmitDialogRequest` structure:
|
||
|
||
```json
|
||
{
|
||
"type": "dialog_lookup",
|
||
"url": "<your data_source_url>",
|
||
"callback_id": "<callback ID>",
|
||
"state": "<state>",
|
||
"user_id": "<user ID>",
|
||
"channel_id": "<channel ID>",
|
||
"team_id": "<team ID>",
|
||
"submission": {
|
||
"query": "user_search_input",
|
||
"selected_field": "dynamic_field",
|
||
"other_field_name": "current_value"
|
||
}
|
||
}
|
||
```
|
||
|
||
The `submission` map contains `query` (the user's search input), `selected_field` (the field being searched), and current values of all other form fields.
|
||
|
||
Your endpoint should respond with an array of options:
|
||
|
||
```json
|
||
{
|
||
"items": [
|
||
{
|
||
"text": "Option 1",
|
||
"value": "option1"
|
||
},
|
||
{
|
||
"text": "Option 2",
|
||
"value": "option2"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
**Security Requirements:**
|
||
- External URLs must use HTTPS
|
||
- Plugin paths (starting with `/plugins/`) are proxied locally and do not require HTTPS
|
||
- The lookup endpoint should validate user permissions
|
||
|
||
**Dynamic select with multiselect:**
|
||
|
||
```json
|
||
{
|
||
"display_name": "Multiple Dynamic Options",
|
||
"name": "multi_dynamic_field",
|
||
"type": "select",
|
||
"multiselect": true,
|
||
"data_source": "dynamic",
|
||
"data_source_url": "https://your-mattermost-server.com/plugins/your-plugin-id/api/lookup",
|
||
"placeholder": "Search and select multiple options..."
|
||
}
|
||
```
|
||
|
||
The `select` element can also be generated dynamically from users and channels of the system.
|
||
|
||
For users, use:
|
||
|
||
```json
|
||
{
|
||
"display_name": "Assignee",
|
||
"name": "assignee",
|
||
"type": "select",
|
||
"data_source": "users"
|
||
}
|
||
```
|
||
|
||
For multiple user selection:
|
||
|
||
```json
|
||
{
|
||
"display_name": "Multiple Assignees",
|
||
"name": "assignees",
|
||
"type": "select",
|
||
"multiselect": true,
|
||
"data_source": "users"
|
||
}
|
||
```
|
||
|
||
For Public channels, use:
|
||
|
||
```json
|
||
{
|
||
"display_name": "Post this message to",
|
||
"name": "channel",
|
||
"type": "select",
|
||
"data_source": "channels"
|
||
}
|
||
```
|
||
|
||
For multiple channel selection:
|
||
|
||
```json
|
||
{
|
||
"display_name": "Post to multiple channels",
|
||
"name": "channels",
|
||
"type": "select",
|
||
"multiselect": true,
|
||
"data_source": "channels"
|
||
}
|
||
```
|
||
|
||
The list of supported fields for the `select` type element is included below:
|
||
|
||
| Field | Type | Description |
|
||
|--------------------|---------|------------------------------------------------------------------------------------------------------------------------------------|
|
||
| `display_name` | String | Display name of the field shown to the user in the dialog. Maximum 24 characters. |
|
||
| `name` | String | Name of the field element used by the integration. Maximum 300 characters. You should use unique `name` fields in the same dialog. |
|
||
| `type` | String | Set this value to `select` for a `select` element. |
|
||
| `multiselect` | Boolean | (Optional) Set to `true` to allow multiple selections from the list. Default is `false`. |
|
||
| `data_source` | String | (Optional) One of `users`, `channels`, or `dynamic`. If none specified, assumes a manual list of options is provided by the integration. |
|
||
| `data_source_url` | String | (Optional) URL for dynamic option loading when `data_source` is `dynamic`. Must be HTTPS or a `/plugins/` path. |
|
||
| `refresh` | Boolean | (Optional) When `true`, triggers a field refresh request to the dialog's `source_url` when this field's value changes. Use this for dependent dropdowns or conditional form fields. Default is `false`. |
|
||
| `optional` | Boolean | (Optional) Set to `true` if this form element is not required. Default is `false`. |
|
||
| `options` | Array | (Optional) An array of options for the select element. Not applicable for `users`, `channels`, or `dynamic` data sources. |
|
||
| `help_text` | String | (Optional) Set help text for this form element. Maximum 150 characters. |
|
||
| `default` | String | (Optional) Set a default value for this form element. For multiselect, use comma-separated values. Maximum 3,000 characters. |
|
||
| `placeholder` | String | (Optional) A string displayed to help guide users in completing the element. Maximum 3,000 characters. |
|
||
|
||
|
||
### Checkbox element
|
||
|
||
From Mattermost v5.16 you can use `checkbox` elements. It looks like a plain text field with a checkbox to be selected. Below is an example of a `checkbox` element that asks for meeting feedback.
|
||
|
||

|
||
|
||
```json
|
||
{
|
||
"display_name": "Can you please select below",
|
||
"placeholder": "The meeting was helpful.",
|
||
"name": "meeting_input",
|
||
"type": "bool"
|
||
}
|
||
```
|
||
|
||
The full list of supported fields is included below:
|
||
|
||
| Field | Type | Description |
|
||
|----------------|---------|------------------------------------------------------------------------------------------------------------------------------------|
|
||
| `display_name` | String | Display name of the field shown to the user in the dialog. Maximum 24 characters. |
|
||
| `name` | String | Name of the field element used by the integration. Maximum 300 characters. You should use unique `name` fields in the same dialog. |
|
||
| `type` | String | Set this value to `bool` for a checkbox element. |
|
||
| `optional` | Boolean | (Optional) Set to `true` if this form element is not required. Default is `false`. |
|
||
| `help_text` | String | (Optional) Set help text for this form element. Maximum 150 characters. |
|
||
| `default` | String | (Optional) Set a default value for this form element. `true` or `false`. |
|
||
| `placeholder` | String | (Optional) A string displayed to include a label besides the checkbox. Maximum 150 characters. |
|
||
|
||
### Radio element
|
||
|
||
From Mattermost v5.16 you can use `radio` elements. It looks like a plain text field with a radio button to be selected. Below is an example of a `radio` element that asks for a department.
|
||
|
||

|
||
|
||
```json
|
||
{
|
||
"display_name": "Which department do you work in?",
|
||
"name": "department",
|
||
"type": "radio",
|
||
"options": [
|
||
{
|
||
"text": "Engineering",
|
||
"value": "engineering"
|
||
},
|
||
{
|
||
"text": "Sales",
|
||
"value": "sales"
|
||
},
|
||
{
|
||
"text": "Administration",
|
||
"value": "administration"
|
||
}
|
||
],
|
||
"help_text": "Please indicate your department as of January 1.",
|
||
"default": "engineering"
|
||
}
|
||
```
|
||
|
||
The full list of supported fields are included below:
|
||
|
||
| Field | Type | Description |
|
||
|----------------|--------|------------------------------------------------------------------------------------------------------------------------------------|
|
||
| `display_name` | String | Display name of the field shown to the user in the dialog. Maximum 24 characters. |
|
||
| `name` | String | Name of the field element used by the integration. Maximum 300 characters. You should use unique `name` fields in the same dialog. |
|
||
| `type` | String | Set this value to `radio` for a radio element. |
|
||
| `options` | Array | (Optional) An array of options for the radio element. |
|
||
| `help_text` | String | (Optional) Set help text for this form element. Maximum 150 characters. |
|
||
| `default` | String | (Optional) Set a default value for this form element. |
|
||
|
||
### Date elements
|
||
##### Minimum Server Version: 11.1
|
||
|
||
Date elements provide native date picker functionality for selecting dates without time information. Below is an example of a `date` element for event scheduling.
|
||
|
||
```json
|
||
{
|
||
"display_name": "Event Date",
|
||
"name": "event_date",
|
||
"type": "date",
|
||
"default": "2024-03-15",
|
||
"placeholder": "Select a date",
|
||
"help_text": "Choose the date for your event",
|
||
"optional": false,
|
||
"datetime_config": {
|
||
"min_date": "today",
|
||
"max_date": "+30d"
|
||
}
|
||
}
|
||
```
|
||
|
||
The full list of supported fields for `date` elements is included below:
|
||
|
||
| Field | Type | Description |
|
||
|-------------------|---------|------------------------------------------------------------------------------------------------------------------------------------|
|
||
| `display_name` | String | Display name of the field shown to the user in the dialog. Maximum 24 characters. |
|
||
| `name` | String | Name of the field element used by the integration. Maximum 300 characters. You should use unique `name` fields in the same dialog. |
|
||
| `type` | String | Set this value to `date` for a date element. |
|
||
| `default` | String | (Optional) Default value in ISO date format (YYYY-MM-DD) or relative format (`today`, `tomorrow`, `+1d`, `+1w`, `+1M`, `+1y`). Full ISO datetime strings are accepted, but only the date part is parsed; timezone information is ignored. |
|
||
| `placeholder` | String | (Optional) Placeholder text shown in the input field. Maximum 150 characters. |
|
||
| `help_text` | String | (Optional) Help text displayed below the field. Maximum 150 characters. |
|
||
| `optional` | Boolean | (Optional) Set to `true` if this form element is not required. Default is `false`. |
|
||
| `datetime_config` | Object | (Optional) Nested date configuration object. See [datetime_config object](#datetime_config-object) for supported properties. |
|
||
| `min_date` | String | (Deprecated — use `datetime_config.min_date`.) Earliest selectable date. Supports ISO date format (YYYY-MM-DD) or relative formats (`today`, `tomorrow`, `+1d`, `-7d`, etc.). Full ISO datetime strings are accepted, but only the date part is parsed; timezone information is ignored. |
|
||
| `max_date` | String | (Deprecated — use `datetime_config.max_date`.) Latest selectable date. Supports ISO date format (YYYY-MM-DD) or relative formats (`today`, `+30d`, `+1y`, etc.). Full ISO datetime strings are accepted, but only the date part is parsed; timezone information is ignored. |
|
||
|
||
#### Date field usage examples
|
||
|
||
**Basic date selection:**
|
||
```json
|
||
{
|
||
"display_name": "Project Deadline",
|
||
"name": "deadline",
|
||
"type": "date",
|
||
"help_text": "When is this project due?",
|
||
"datetime_config": {
|
||
"min_date": "today"
|
||
},
|
||
"optional": false
|
||
}
|
||
```
|
||
|
||
**Date range with relative defaults:**
|
||
```json
|
||
{
|
||
"display_name": "Flexible Date",
|
||
"name": "any_date",
|
||
"type": "date",
|
||
"help_text": "Any date within the next year",
|
||
"datetime_config": {
|
||
"min_date": "today",
|
||
"max_date": "+1y"
|
||
},
|
||
"default": "+1w",
|
||
"optional": true
|
||
}
|
||
```
|
||
|
||
### DateTime elements
|
||
##### Minimum Server Version: 11.1
|
||
|
||
DateTime elements provide combined date and time picker functionality with timezone support. Below is an example of a `datetime` element for meeting scheduling.
|
||
|
||
```json
|
||
{
|
||
"display_name": "Meeting Time",
|
||
"name": "meeting_time",
|
||
"type": "datetime",
|
||
"default": "2024-03-15T14:30:00Z",
|
||
"placeholder": "Select date and time",
|
||
"help_text": "Choose when the meeting should start",
|
||
"optional": false,
|
||
"datetime_config": {
|
||
"min_date": "today",
|
||
"max_date": "+7d",
|
||
"time_interval": 30
|
||
}
|
||
}
|
||
```
|
||
|
||
The full list of supported fields for `datetime` elements is included below:
|
||
|
||
| Field | Type | Description |
|
||
|-------------------|---------|------------------------------------------------------------------------------------------------------------------------------------|
|
||
| `display_name` | String | Display name of the field shown to the user in the dialog. Maximum 24 characters. |
|
||
| `name` | String | Name of the field element used by the integration. Maximum 300 characters. You should use unique `name` fields in the same dialog. |
|
||
| `type` | String | Set this value to `datetime` for a datetime element. |
|
||
| `default` | String | (Optional) Default value in ISO datetime format (RFC3339) or relative format. For relative dates, time defaults to noon. When specifying a time, it must align with `datetime_config.time_interval` (be a multiple of the interval). |
|
||
| `placeholder` | String | (Optional) Placeholder text shown in the input field. Maximum 150 characters. |
|
||
| `help_text` | String | (Optional) Help text displayed below the field. Maximum 150 characters. |
|
||
| `optional` | Boolean | (Optional) Set to `true` if this form element is not required. Default is `false`. |
|
||
| `datetime_config` | Object | (Optional) Nested datetime configuration object. See [datetime_config object](#datetime_config-object) for supported properties. |
|
||
| `min_date` | String | (Deprecated — use `datetime_config.min_date`.) Earliest selectable date. Supports ISO format or relative formats (`today`, `tomorrow`, `+1d`, `-7d`, etc.). |
|
||
| `max_date` | String | (Deprecated — use `datetime_config.max_date`.) Latest selectable date. Supports ISO format or relative formats (`today`, `+30d`, `+1y`, etc.). |
|
||
| `time_interval` | Integer | (Deprecated — use `datetime_config.time_interval`.) Time selection interval in minutes. Must be between 1 and 1440, and must be a divisor of 1440 to create evenly spaced intervals throughout the day. Common values: 15, 30, 60, 90, 120. Default is 60. |
|
||
|
||
#### DateTime field usage examples
|
||
|
||
**Meeting scheduler with business hours:**
|
||
```json
|
||
{
|
||
"display_name": "Meeting Time",
|
||
"name": "meeting_time",
|
||
"type": "datetime",
|
||
"help_text": "Select a time during business hours",
|
||
"datetime_config": {
|
||
"min_date": "+1d",
|
||
"max_date": "+14d",
|
||
"time_interval": 30
|
||
},
|
||
"optional": false
|
||
}
|
||
```
|
||
|
||
**Event with custom time intervals:**
|
||
```json
|
||
{
|
||
"display_name": "Event Start Time",
|
||
"name": "event_start",
|
||
"type": "datetime",
|
||
"help_text": "When does your event begin?",
|
||
"datetime_config": {
|
||
"min_date": "today",
|
||
"max_date": "+90d",
|
||
"time_interval": 15
|
||
},
|
||
"default": "today"
|
||
}
|
||
```
|
||
|
||
**Fixed location timezone with manual entry:**
|
||
```json
|
||
{
|
||
"display_name": "Conference Start",
|
||
"name": "conference_start",
|
||
"type": "datetime",
|
||
"help_text": "All attendees see this time in the conference timezone",
|
||
"datetime_config": {
|
||
"location_timezone": "America/Denver",
|
||
"manual_time_entry": true,
|
||
"time_interval": 30
|
||
}
|
||
}
|
||
```
|
||
|
||
#### datetime_config object
|
||
##### Minimum Server Version: 11.6
|
||
|
||
The `datetime_config` object groups date/datetime configuration into a single nested structure. It is supported on both `date` and `datetime` elements.
|
||
|
||
| Field | Type | Applies to | Since | Description |
|
||
|---------------------------|---------|--------------------|--------|-----------------------------------------------------------------------------------------------------------------------------|
|
||
| `min_date` | String | `date`, `datetime` | 11.8 | (Optional) Earliest selectable date. Supports ISO format or relative formats (`today`, `+1d`, etc.). |
|
||
| `max_date` | String | `date`, `datetime` | 11.8 | (Optional) Latest selectable date. Supports ISO format or relative formats (`+30d`, `+1y`, etc.). |
|
||
| `time_interval` | Integer | `datetime` | 11.6 | (Optional) Time selection interval in minutes. Must be between 1 and 1440, and must be a divisor of 1440. Default is 60. |
|
||
| `location_timezone` | String | `datetime` | 11.6 | (Optional) IANA timezone used to display and submit the time (e.g. `America/Denver`, `Asia/Tokyo`). When set, all users see the same wall-clock time regardless of their own timezone. Defaults to the viewing user's timezone. |
|
||
| `manual_time_entry` | Boolean | `datetime` | 11.8 | (Optional) When `true`, users can type the time directly in addition to using the dropdown. Default is `false`. |
|
||
| `allow_manual_time_entry` | Boolean | `datetime` | 11.6 (deprecated in 11.8) | (Deprecated — use `manual_time_entry`.) When both are set, either enabling turns the feature on. |
|
||
|
||
**Backward compatibility (new in 11.8):** The top-level `min_date`, `max_date`, and `time_interval` fields on `date` and `datetime` elements are still accepted for existing integrations, but are deprecated in favor of `datetime_config`. When both are provided on the same element, values inside `datetime_config` take precedence over the legacy top-level values.
|
||
|
||
#### Date and DateTime field specifications
|
||
|
||
**Relative Date Formats:**
|
||
- `today`: Current date
|
||
- `tomorrow`: Next day
|
||
- `yesterday`: Previous day
|
||
- `+Nd`: N days from today (e.g., `+1d`, `+7d`)
|
||
- `+Nw`: N weeks from today (e.g., `+1w`, `+2w`)
|
||
- `+NM`: N months from today (e.g., `+1M`, `+6M`)
|
||
- `+Ny`: N years from today (e.g., `+1y`)
|
||
- `-Nd`: N days ago (e.g., `-1d`, `-7d`)
|
||
|
||
**ISO Format Examples:**
|
||
- Date: `2024-03-15` (YYYY-MM-DD)
|
||
- DateTime: `2024-03-15T14:30:00Z` (RFC3339 format)
|
||
- DateTime with timezone: `2024-03-15T14:30:00-05:00`
|
||
|
||
**Form Submission Format:**
|
||
- Date fields submit in ISO date format: `2024-03-15`
|
||
- DateTime fields submit in RFC3339 format with user's timezone: `2024-03-15T14:30:00-05:00`
|
||
|
||
**Localization:**
|
||
- Date fields automatically format according to user's locale (e.g., "Mar 15, 2024" for en-US)
|
||
- DateTime fields respect user's 12/24 hour preference and locale-specific formatting
|
||
- Time picker displays times according to user's timezone
|
||
|
||
**Validation:**
|
||
- Client validates date formats and range constraints
|
||
- Server validates relative date resolution and field configuration
|
||
- For datetime fields, `datetime_config.time_interval` must be a divisor of 1440 (24 hours in minutes)
|
||
- Default times must align with the effective `time_interval` (be a multiple of the interval)
|
||
- Invalid dates, times, or out-of-range selections show appropriate error messages
|
||
|
||
**Time Interval Examples:**
|
||
- `"time_interval": 15` creates options: 00:00, 00:15, 00:30, 00:45, 01:00, etc.
|
||
- `"time_interval": 30` creates options: 00:00, 00:30, 01:00, 01:30, etc.
|
||
- `"time_interval": 60` creates options: 00:00, 01:00, 02:00, 03:00, etc.
|
||
- Invalid: `"time_interval": 7` (7 is not a divisor of 1440)
|
||
|
||
### File elements
|
||
#### Minimum Server Version: 11.10
|
||
|
||
File elements allow users to upload one or more files as part of an interactive dialog submission. Below is an example of a `file` element that requests a single file attachment.
|
||
|
||
```json
|
||
{
|
||
"display_name": "Attachment",
|
||
"name": "attachment",
|
||
"type": "file",
|
||
"optional": true
|
||
}
|
||
```
|
||
|
||
To allow multiple file uploads, set `allow_multiple` to `true`:
|
||
|
||
```json
|
||
{
|
||
"display_name": "Attachments",
|
||
"name": "attachments",
|
||
"type": "file",
|
||
"allow_multiple": true,
|
||
"optional": true
|
||
}
|
||
```
|
||
|
||
The full list of supported fields is included below:
|
||
|
||
| Field | Type | Description |
|
||
|------------------|---------|------------------------------------------------------------------------------------------------------------------------------------|
|
||
| `display_name` | String | Display name of the field shown to the user in the dialog. Maximum 24 characters. |
|
||
| `name` | String | Name of the field element used by the integration. Maximum 300 characters. You should use unique `name` fields in the same dialog. |
|
||
| `type` | String | Set this value to `file` for a file upload element. |
|
||
| `optional` | Boolean | (Optional) Set to `true` if this form element is not required. Default is `false`. |
|
||
| `help_text` | String | (Optional) Set help text for this form element. Maximum 150 characters. |
|
||
| `default` | String | (Optional) Comma-separated list of file IDs, from files the user previously uploaded, used to pre-populate the field. Limited to a single ID unless `allow_multiple` is `true`, and no more than 10 IDs. Maximum 300 characters. |
|
||
| `placeholder` | String | (Optional) Hint text shown beneath the upload button while no file is selected. Maximum 300 characters. |
|
||
| `allow_multiple` | Boolean | (Optional) Set to `true` to allow the user to upload more than one file. Default is `false`. |
|
||
|
||
#### File upload limits
|
||
|
||
- A maximum of 10 file IDs may be submitted per dialog submission.
|
||
- The server validates that each submitted file ID was uploaded by the submitting user. Referencing a file uploaded by a different user will be rejected.
|
||
- Duplicate file IDs are automatically deduplicated before validation.
|
||
|
||
#### File IDs in the submission payload
|
||
|
||
When a dialog containing file elements is submitted, the uploaded file IDs are sent in a top-level `file_ids` array alongside the standard `submission` map. Use `file_ids` as the authoritative source of uploaded file IDs — each ID can be used with the [Files API](https://api.mattermost.com/#tag/files) to attach files to posts or retrieve file metadata.
|
||
|
||
### Action button elements
|
||
#### Minimum Server Version: 11.10
|
||
|
||
Action button elements render a clickable button inside a dialog. Instead of submitting the current dialog, clicking the button asks your integration to open a *child* dialog that is stacked on top of the current one. Use this to branch into a follow-up workflow (for example, "Add another item" or "Configure advanced options") while preserving the dialog the user is already working in.
|
||
|
||
```json
|
||
{
|
||
"display_name": "Add attachment",
|
||
"name": "add_attachment",
|
||
"type": "action_button",
|
||
"action_button": {
|
||
"url": "https://your-mattermost-server.com/plugins/your-plugin-id/api/attach",
|
||
"context": {
|
||
"action": "open_attachment_dialog"
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
The full list of supported fields is included below:
|
||
|
||
| Field | Type | Description |
|
||
|-----------------|--------|--------------------------------------------------------------------------------------------------------------------------------------------------|
|
||
| `display_name` | String | Display name shown on the button. Maximum 24 characters. |
|
||
| `name` | String | Name of the field element used by the integration. Maximum 300 characters. You should use unique `name` fields in the same dialog. |
|
||
| `type` | String | Set this value to `action_button` for an action button element. |
|
||
| `action_button` | Object | Action button configuration. Required for this element type. See the fields below. |
|
||
|
||
The `action_button` object supports:
|
||
|
||
| Field | Type | Description |
|
||
|-----------|--------|---------------------------------------------------------------------------------------------------------------------------------------|
|
||
| `url` | String | The URL the action is sent to when the button is clicked. Required. Must be a valid lookup URL — an HTTPS URL or a `/plugins/` path. |
|
||
| `context` | Object | (Optional) String map of arbitrary key/value pairs forwarded to your integration when the button is clicked. Use this to identify which button was pressed or to carry state. |
|
||
|
||
Action button elements are not input fields: their values are never included in the dialog submission payload, and they are not subject to the required/optional validation applied to other elements.
|
||
|
||
#### Action button flow
|
||
|
||
When a user clicks an action button, the Mattermost client sends an `HTTP POST` to the `/api/v4/actions/dialogs/execute` endpoint. The server validates the request, generates a new trigger ID, and forwards the button's `context` to the `url` configured on the button. The payload your integration receives is a `PostActionIntegrationRequest`:
|
||
|
||
```json
|
||
{
|
||
"type": "dialog_action",
|
||
"trigger_id": "<new trigger ID generated by the server>",
|
||
"user_id": "<user ID of the user who clicked the button>",
|
||
"user_name": "<username of that user>",
|
||
"channel_id": "<channel ID the user clicked the button from>",
|
||
"channel_name": "<name of that channel>",
|
||
"team_id": "<team ID the channel belongs to, empty for DM/GM channels>",
|
||
"team_name": "<name of that team, empty for DM/GM channels>",
|
||
"context": {
|
||
"action": "open_attachment_dialog"
|
||
}
|
||
}
|
||
```
|
||
|
||
Use the `trigger_id` from this payload to [open a child dialog](#open-a-dialog) — send an `HTTP POST` to `/api/v4/actions/dialogs/open` exactly as you would for a top-level dialog. The child dialog is displayed stacked on top of the dialog the user clicked the button in.
|
||
|
||
:::note
|
||
Up to three dialogs may be open at once. If three dialogs are already open, the request to open a further child dialog is silently ignored by the client, so design your workflows to stay within this limit.
|
||
:::
|
||
|
||
## Dialog submission
|
||
|
||
When a user submits a dialog, Mattermost will perform client-side input validation to make sure:
|
||
|
||
- All required fields are filled.
|
||
- All formats are correct (e.g. email, telephone number, etc.).
|
||
|
||
The submission payload sent to the integration is:
|
||
|
||
```json
|
||
{
|
||
"type": "dialog_submission",
|
||
"callback_id": "<callback ID provided by the integration>",
|
||
"state": "<state provided by the integration>",
|
||
"user_id": "<user ID of the user who submitted the dialog>",
|
||
"channel_id": "<channel ID the user was in when submitting the dialog>",
|
||
"team_id": "<team ID the channel belongs to, empty for DM/GM channels>",
|
||
"submission": {
|
||
"some_element_name": "<value of that element>",
|
||
"some_other_element": "<value of some other element>"
|
||
},
|
||
"file_ids": ["<file ID 1>", "<file ID 2>"],
|
||
"cancelled": false
|
||
}
|
||
```
|
||
|
||
:::note[`team_id` behavior change (server version 11.10)]
|
||
For the `/api/v4/actions/dialogs/submit`, `/api/v4/actions/dialogs/lookup`, and `/api/v4/actions/dialogs/execute` endpoints, the `team_id` forwarded to your integration is now always derived by the server from the channel the dialog was opened in, rather than from the value supplied by the client. Any client-supplied `team_id` is ignored. For direct (DM) and group (GM) message channels — which do not belong to a team — `team_id` is sent as an empty string. If your integration previously relied on a client-supplied `team_id` for team-specific logic, update it to use this channel-derived value (and to handle the empty case for DM/GM channels).
|
||
:::
|
||
|
||
Optionally, the dialog can send an event back to the integration if `notify_on_cancel` parameter is set to `true`. If this happens, `cancelled` will be set to `true` on the above payload, and `submission` will be empty.
|
||
|
||
Moreover, Mattermost also allows the integration itself to perform input validation. This can be done by responding to the dialog submission request with a JSON body containing an `errors` field. The `errors` field can contain a JSON object, mapping input field names to string error messages you would like to display to the user. For example, if you have a field named `num_between_0_and_10`, you can enforce the user to enter a number between 0 and 10 by returning the following response body if the condition isn't satisfied:
|
||
|
||
```json
|
||
{"errors": {"num_between_0_and_10": "Enter a number between 0 and 10."}}
|
||
```
|
||
|
||
The integration may also return a generic error message to the user that is not attached to a specific field. This can be done by responding to the dialog submission request with a JSON body containing an `error` field. The `error` field should contain a string with the error message to display to the user. For example, if a server-side error occurs, you can return a message explaining it:
|
||
|
||
```json
|
||
{"error": "Failed to fetch additional data. Please try again."}
|
||
```
|
||
|
||
Support for generic error messages was added in Mattermost v5.18.
|
||
|
||
Finally, once the request is submitted, we recommend that the integration responds with a system message or an ephemeral message confirming the submission. This should be a separate request back to Mattermost once the service has received and responded to a submission request from a dialog. This can be done either via [the REST API](https://api.mattermost.com/#tag/posts%2Fpaths%2F~1posts~1ephemeral%2Fpost), or via the [Plugin API](/developers/integrate/reference/server#API.SendEphemeralPost) if you're developing a plugin.
|
||
|
||
## Multi-step dialogs
|
||
##### Minimum Server Version: 11.1
|
||
|
||
Multi-step dialogs enable wizard-like form experiences where users progress through multiple steps to complete a complex workflow. Each step can have different fields, and form values are accumulated across steps.
|
||
|
||
Multi-step behavior is achieved by having your submit handler return a new form instead of closing the dialog. No special dialog property is required.
|
||
|
||
### Multi-step workflow
|
||
|
||
1. **Initial dialog**: Open a normal dialog with the first step's elements. Use the `state` field to track which step you're on (e.g., `"step_1"`).
|
||
2. **Step submission**: When the user clicks Submit, your integration receives a standard `dialog_submission` request with `type: "dialog_submission"`.
|
||
3. **Return next step**: Instead of returning an empty response (which closes the dialog), return a response with `type: "form"` and a `form` object containing the next step's dialog definition.
|
||
4. **Value accumulation**: The client automatically accumulates submission values across steps. Each step's submission includes all values from previous steps plus the current step.
|
||
5. **Final submission**: On the last step, return an empty response (HTTP 200) or `{"type": "ok"}` to close the dialog.
|
||
|
||
### Multi-step submission handling
|
||
|
||
Each step submission uses the standard dialog submission format:
|
||
|
||
```json
|
||
{
|
||
"type": "dialog_submission",
|
||
"callback_id": "<callback ID>",
|
||
"state": "step_1",
|
||
"user_id": "<user ID>",
|
||
"channel_id": "<channel ID>",
|
||
"team_id": "<team ID>",
|
||
"submission": {
|
||
"step1_field": "value_from_step_1"
|
||
},
|
||
"cancelled": false
|
||
}
|
||
```
|
||
|
||
To advance to the next step, your integration responds with a new form:
|
||
|
||
```json
|
||
{
|
||
"type": "form",
|
||
"form": {
|
||
"callback_id": "multistep_wizard",
|
||
"title": "Setup Wizard - Step 2 of 3",
|
||
"elements": [
|
||
{
|
||
"display_name": "Step 2 Field",
|
||
"name": "step2_field",
|
||
"type": "text"
|
||
}
|
||
],
|
||
"submit_label": "Next",
|
||
"state": "step_2"
|
||
}
|
||
}
|
||
```
|
||
|
||
On the final step, the submission includes accumulated values from all steps:
|
||
|
||
```json
|
||
{
|
||
"type": "dialog_submission",
|
||
"callback_id": "<callback ID>",
|
||
"state": "step_3",
|
||
"user_id": "<user ID>",
|
||
"channel_id": "<channel ID>",
|
||
"team_id": "<team ID>",
|
||
"submission": {
|
||
"step1_field": "value_from_step_1",
|
||
"step2_field": "value_from_step_2",
|
||
"step3_field": "value_from_step_3"
|
||
},
|
||
"cancelled": false
|
||
}
|
||
```
|
||
|
||
Return an empty response (HTTP 200 with empty body) or `{"type": "ok"}` to close the dialog.
|
||
|
||
### Multi-step example
|
||
|
||
```json
|
||
{
|
||
"trigger_id": "trigger_id_here",
|
||
"url": "https://your-integration.com/dialog",
|
||
"dialog": {
|
||
"callback_id": "multistep_wizard",
|
||
"title": "Setup Wizard - Step 1 of 3",
|
||
"introduction_text": "Welcome to the setup wizard",
|
||
"elements": [
|
||
{
|
||
"display_name": "Project Name",
|
||
"name": "project_name",
|
||
"type": "text",
|
||
"placeholder": "Enter project name"
|
||
}
|
||
],
|
||
"submit_label": "Next",
|
||
"state": "step_1"
|
||
}
|
||
}
|
||
```
|
||
|
||
## Dynamic field refresh
|
||
##### Minimum Server Version: 11.1
|
||
|
||
Interactive dialogs support dynamic field refresh functionality, allowing fields to be updated based on user input. This is useful for dependent dropdowns or conditional form fields.
|
||
|
||
To enable field refresh, two things are required:
|
||
1. Set `refresh: true` on the **element** that should trigger refreshes when its value changes.
|
||
2. Set `source_url` on the **dialog** to specify where refresh requests are sent.
|
||
|
||
When a user changes a select element that has `refresh: true`, Mattermost sends a request to the dialog's `source_url` via the `/api/v4/actions/dialogs/submit` endpoint.
|
||
|
||
### Field refresh webhook
|
||
|
||
The field refresh request uses the standard `SubmitDialogRequest` structure with `type` set to `"refresh"`:
|
||
|
||
```json
|
||
{
|
||
"type": "refresh",
|
||
"url": "<source_url>",
|
||
"callback_id": "<callback ID>",
|
||
"state": "<current state>",
|
||
"user_id": "<user ID>",
|
||
"channel_id": "<channel ID>",
|
||
"team_id": "<team ID>",
|
||
"submission": {
|
||
"category": "software",
|
||
"subcategory": "",
|
||
"selected_field": "category"
|
||
}
|
||
}
|
||
```
|
||
|
||
The `submission` map contains the current values of all form fields, plus a `selected_field` key indicating which field triggered the refresh. Cleared fields are sent as empty strings.
|
||
|
||
Your integration should respond with a complete updated dialog wrapped in a `form` response:
|
||
|
||
```json
|
||
{
|
||
"type": "form",
|
||
"form": {
|
||
"callback_id": "dynamic_form",
|
||
"title": "Dynamic Form",
|
||
"source_url": "/plugins/your-plugin-id/refresh",
|
||
"elements": [
|
||
{
|
||
"display_name": "Category",
|
||
"name": "category",
|
||
"type": "select",
|
||
"refresh": true,
|
||
"options": [
|
||
{"text": "Software", "value": "software"},
|
||
{"text": "Hardware", "value": "hardware"}
|
||
]
|
||
},
|
||
{
|
||
"display_name": "Subcategory",
|
||
"name": "subcategory",
|
||
"type": "select",
|
||
"options": [
|
||
{"text": "Frontend", "value": "frontend"},
|
||
{"text": "Backend", "value": "backend"}
|
||
]
|
||
}
|
||
],
|
||
"submit_label": "Submit",
|
||
"state": "step_1"
|
||
}
|
||
}
|
||
```
|
||
|
||
The response replaces the entire dialog with the new form definition. The client preserves the user's current field values where field names match.
|
||
|
||
### Field refresh example
|
||
|
||
```json
|
||
{
|
||
"trigger_id": "trigger_id_here",
|
||
"url": "https://your-integration.com/dialog/submit",
|
||
"dialog": {
|
||
"callback_id": "dynamic_form",
|
||
"title": "Dynamic Form",
|
||
"source_url": "/plugins/your-plugin-id/refresh",
|
||
"elements": [
|
||
{
|
||
"display_name": "Category",
|
||
"name": "category",
|
||
"type": "select",
|
||
"refresh": true,
|
||
"options": [
|
||
{"text": "Software", "value": "software"},
|
||
{"text": "Hardware", "value": "hardware"}
|
||
]
|
||
},
|
||
{
|
||
"display_name": "Subcategory",
|
||
"name": "subcategory",
|
||
"type": "select",
|
||
"options": []
|
||
}
|
||
],
|
||
"submit_label": "Submit",
|
||
"state": "step_1"
|
||
}
|
||
}
|
||
```
|
||
|
||
|
||
<Note title="Note">
|
||
If the dialog is closed by clicking **Cancel** or **X**, no data will be submitted. If a user clicks away from the dialog, the dialog won’t close. This is to prevent accidentally losing any answers they've made to an unsubmitted dialog.
|
||
</Note>
|
||
|
||
|
||
## Example
|
||
|
||
Below is a full example of a JSON payload that creates an interactive dialog in Mattermost:
|
||
|
||
```json
|
||
{
|
||
"trigger_id":"nbt1dxzqwpn6by14sfs66ganhc",
|
||
"url":"http://localhost:5000/dialog_submit",
|
||
"dialog":{
|
||
"callback_id":"somecallbackid",
|
||
"title":"Test Title",
|
||
"icon_url":"https://mattermost.com/wp-content/uploads/2022/02/icon.png",
|
||
"elements":[
|
||
{
|
||
"display_name":"Display Name",
|
||
"name":"realname",
|
||
"type":"text",
|
||
"subtype":"",
|
||
"default":"default text",
|
||
"placeholder":"placeholder",
|
||
"help_text":"This a regular input in an interactive dialog triggered by a test integration.",
|
||
"optional":false,
|
||
"min_length":0,
|
||
"max_length":0,
|
||
"data_source":"",
|
||
"options":null
|
||
},
|
||
{
|
||
"display_name":"Email",
|
||
"name":"someemail",
|
||
"type":"text",
|
||
"subtype":"email",
|
||
"default":"",
|
||
"placeholder":"placeholder@bladekick.com",
|
||
"help_text":"This a regular email input in an interactive dialog triggered by a test integration.",
|
||
"optional":false,
|
||
"min_length":0,
|
||
"max_length":0,
|
||
"data_source":"",
|
||
"options":null
|
||
},
|
||
{
|
||
"display_name":"Number",
|
||
"name":"somenumber",
|
||
"type":"text",
|
||
"subtype":"number",
|
||
"default":"",
|
||
"placeholder":"",
|
||
"help_text":"",
|
||
"optional":false,
|
||
"min_length":0,
|
||
"max_length":0,
|
||
"data_source":"",
|
||
"options":null
|
||
},
|
||
{
|
||
"display_name":"Display Name Long Text Area",
|
||
"name":"realnametextarea",
|
||
"type":"textarea",
|
||
"subtype":"",
|
||
"default":"",
|
||
"placeholder":"placeholder",
|
||
"help_text":"",
|
||
"optional":true,
|
||
"min_length":5,
|
||
"max_length":100,
|
||
"data_source":"",
|
||
"options":null
|
||
},
|
||
{
|
||
"display_name":"User Selector",
|
||
"name":"someuserselector",
|
||
"type":"select",
|
||
"subtype":"",
|
||
"default":"",
|
||
"placeholder":"Select a user...",
|
||
"help_text":"",
|
||
"optional":false,
|
||
"min_length":0,
|
||
"max_length":0,
|
||
"data_source":"users",
|
||
"options":null
|
||
},
|
||
{
|
||
"display_name":"Channel Selector",
|
||
"name":"somechannelselector",
|
||
"type":"select",
|
||
"subtype":"",
|
||
"default":"",
|
||
"placeholder":"Select a channel...",
|
||
"help_text":"Choose a channel from the list.",
|
||
"optional":true,
|
||
"min_length":0,
|
||
"max_length":0,
|
||
"data_source":"channels",
|
||
"options":null
|
||
},
|
||
{
|
||
"display_name":"Option Selector",
|
||
"name":"someoptionselector",
|
||
"type":"select",
|
||
"subtype":"",
|
||
"default":"",
|
||
"placeholder":"Select an option...",
|
||
"help_text":"",
|
||
"optional":false,
|
||
"min_length":0,
|
||
"max_length":0,
|
||
"data_source":"",
|
||
"options":[
|
||
{
|
||
"text":"Option1",
|
||
"value":"opt1"
|
||
},
|
||
{
|
||
"text":"Option2",
|
||
"value":"opt2"
|
||
},
|
||
{
|
||
"text":"Option3",
|
||
"value":"opt3"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"display_name":"Multiple Option Selector",
|
||
"name":"somemultioptionselector",
|
||
"type":"select",
|
||
"multiselect":true,
|
||
"default":"opt1,opt3",
|
||
"placeholder":"Select multiple options...",
|
||
"help_text":"You can select multiple options from this list.",
|
||
"optional":true,
|
||
"data_source":"",
|
||
"options":[
|
||
{
|
||
"text":"Option1",
|
||
"value":"opt1"
|
||
},
|
||
{
|
||
"text":"Option2",
|
||
"value":"opt2"
|
||
},
|
||
{
|
||
"text":"Option3",
|
||
"value":"opt3"
|
||
},
|
||
{
|
||
"text":"Option4",
|
||
"value":"opt4"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"display_name":"Dynamic Lookup",
|
||
"name":"somedynamicfield",
|
||
"type":"select",
|
||
"data_source":"dynamic",
|
||
"data_source_url":"https://your-mattermost-server.com/plugins/your-plugin-id/api/lookup",
|
||
"placeholder":"Search for dynamic options...",
|
||
"help_text":"Type to search for options from external API",
|
||
"optional":true
|
||
},
|
||
{
|
||
"display_name":"Event Date",
|
||
"name":"eventdate",
|
||
"type":"date",
|
||
"default":"today",
|
||
"placeholder":"Select event date",
|
||
"help_text":"Choose when your event takes place",
|
||
"datetime_config":{
|
||
"min_date":"today",
|
||
"max_date":"+30d"
|
||
},
|
||
"optional":false
|
||
},
|
||
{
|
||
"display_name":"Meeting Time",
|
||
"name":"meetingtime",
|
||
"type":"datetime",
|
||
"default":"",
|
||
"placeholder":"Select meeting date and time",
|
||
"help_text":"Schedule your meeting with date and time",
|
||
"datetime_config":{
|
||
"min_date":"today",
|
||
"max_date":"+14d",
|
||
"time_interval":30
|
||
},
|
||
"optional":true
|
||
}
|
||
],
|
||
"submit_label":"Submit",
|
||
"notify_on_cancel":true,
|
||
"state":"somestate"
|
||
}
|
||
}
|
||
```
|
||
|
||

|
||
|
||
## Share your integration
|
||
|
||
If you've built an integration for Mattermost, please consider [sharing your work](/developers/integrate/getting-started) in our [app directory](https://mattermost.com/marketplace/).
|
||
|
||
The [app directory](https://mattermost.com/marketplace/) lists open source integrations developed by the Mattermost community and are available for download, customization and deployment to your private cloud or self-hosted infrastructure.
|
||
|
||
## Slack compatibility
|
||
|
||
Like Slack, dialogs are triggered by an interactive message menu or button, or by a custom slash command. Additionally, Mattermost can trigger dialogs via plugins.
|
||
|
||
The schema for these objects is the same as Slack's, except for the following differences:
|
||
|
||
- `url` field must be specified for Mattermost dialogs, which specifies where the request is sent to. In Slack, this is handled by specifying the URL within the Slack app that uses the dialog.
|
||
- `icon_url` is an optional field to set the icon for Mattermost dialogs. In Slack, the dialogs use the icon set for the app that uses the dialog.
|
||
- `label` in Slack dialogs is `display_name` in Mattermost dialogs for a more consistent naming convention with other integration types.
|
||
- `hint` in Slack dialogs is `help_text` in Mattermost dialogs for a more consistent naming convention with other integration types.
|
||
- `value` in Slack dialogs is `default` in Mattermost dialogs for a more consistent naming convention with other integration types.
|
||
|
||
Moreover, the JSON payload for `select` type elements matches [interactive message menus](/developers/integrate/plugins/interactive-messages).
|