Dialogs are designed to help you gather multi-part input from end-users in a structured way; think, for example, of a helpdesk ticket that contains a freeform description of an issue, but also requires some category labels for triage.
They're best used for quick, contextual work: brief tasks that get some benefit from being completed in the context of a channel or conversation.
Users trigger your app's dialogs by clicking on buttons, selecting from menus, or invoking slash commands. Dialogs contain a variety of guided input types.
Dialogs appear as a modal window inside Slack. Within that modal, you can add one or many input fields in the form of single line text inputs, text areas, and dropdowns.
The dialog experience focuses squarely on the task at hand. User input is validated before being sent back to your app.
Dialogs are part of the interactive framework already powering message menus and buttons.
While many aspects of dialog development are similar, the JSON used to compose a form differs significantly from interactive message components.
To continue interacting with a user after form submission, your app will need to create new messages or utilize the response_url
associated with the interaction that originally spawned the dialog.
Apps can invoke dialogs when users interact with slash commands, message buttons, or message menus. Each interaction will include a trigger_id
, a kind of short-lived pointer to interaction's who, what, where, and when. Form submissions deliver to the Request URL associated with your Slack app.
Dialogs may contain a careful mixture of standard inputs: short text entry, long-form text areas, and drop-down menus. More are on the way.
Most developers building and handling dialogs will follow steps similar to these:
trigger_id
in the command invocation or interactive action payload.dialog.open
to initiate a dialog in context with the user, providing a trigger_id
and desired form elements.You'll need to create, configure, and install a Slack app before getting started with dialogs. Legacy custom integrations are not supported.
At minimum, you must configure the Interactive Components section of app management. Follow the UI's instructions to provide a Request URL to receive form submissions and other interactions.
If you will use a slash command to initiate dialogs, you will also need to configure your app's slash command.
It is necessary to reinstall your app after adding features and capabilities.
A dialog cannot be invoked without first being initiated by a message interaction or a slash command. That means a user needs to interact with a message button, message menu, or slash command provided by your app before they can engage with any dialog experiences your app provides.
Slack attaches a trigger_id
value as part of all interaction payloads you receive, which acts as a pointer to a specific moment in the space-Slack-time continuum where a user interacted with your app.
Here's an example of an interactive message action containing a trigger_id
:
{
"actions": [
{
"name": "channels_list",
"selected_options": [
{
"value": "C123ABC456"
}
]
}
],
"callback_id": "select_simple_1234",
"team": {
"id": "T0123ABC456",
"domain": "pocket-calculator"
},
"channel": {
"id": "C0123ABC456",
"name": "general"
},
"user": {
"id": "U123ABC456",
"name": "musik"
},
"action_ts": "1481579588.685999",
"message_ts": "1481579582.000003",
"attachment_id": "1",
"token": "iUeRJkkRC9RMMvSRTd8gdq2m",
"response_url": "https://hooks.slack.com/actions/T0123ABC456/123456789/JpmK0yzoZDeRiqfeduTBYXWQ",
"trigger_id": "13345224609.738474920.8088930838d88f008e0"
}
And here's an example of a slash command execution containing a trigger_id
:
token=gIkuvaNzQIHg97ATvDxqgjtO
team_id=T0001
team_domain=example
enterprise_id=E0001
enterprise_name=Globular%20Construct%20Inc
channel_id=C123ABC456
channel_name=test
user_id=U123ABC456
user_name=Steve
command=/weather
text=94070
response_url=https://hooks.slack.com/commands/1234/5678
trigger_id=13345224609.738474920.8088930838d88f008e0
These interactions are the inciting event to your app opening a dialog. The trigger_id
is the key to unlock your app's momentary, focused dialog functionality. Because the trigger_id
expires in 3 seconds, you must exchange the trigger to open a dialog in the given time interval. Using an expired trigger causes the trigger_expired
error.
Use dialog.open
soon after receiving a trigger_id
. Triggers expire 3 seconds after being issued to your app.
To begin a modal dialog, call the dialog.open
method.
As with all of our Web API methods, dialog.open
typically takes URL-encoded parameters as arguments. We also support posting JSON.
The easiest way to open a dialog is to send a POST with a Content-type
HTTP header set to application/json
and a raw POST body containing your dialog's JSON presented as the dialog
argument:
{
"trigger_id": "13345224609.738474920.8088930838d88f008e0",
"dialog": {
"callback_id": "ryde-46e2b0",
"title": "Request a Ride",
"submit_label": "Request",
"notify_on_cancel": true,
"state": "Limo",
"elements": [
{
"type": "text",
"label": "Pickup Location",
"name": "loc_origin"
},
{
"type": "text",
"label": "Dropoff Location",
"name": "loc_destination"
}
]
}
}
See this section on HTTP POST bodies for any needed instruction.
A more complicated way to open dialogs is by sending your carefully crafted JSON as an application/x-www-form-urlencoded
query parameter.
Similar to chat.postMessage
, chat.unfurl
, and chat.update
this method also includes a parameter that expects a JSON object encoded with application/x-www-form-urlencoded
.
A form you might create could be modeled in JSON as:
{
"callback_id": "ryde-46e2b0",
"title": "Request a Ride",
"submit_label": "Request",
"notify_on_cancel": true,
"state": "Limo",
"elements": [
{
"type": "text",
"label": "Pickup Location",
"name": "loc_origin"
},
{
"type": "text",
"label": "Dropoff Location",
"name": "loc_destination"
}
]
}
To prepare that as a HTTP POST to dialog.open
, you'd optionally minify and then URL encode that JSON to a single string, displayed below as the value for the dialog
POST body parameter.
POST /api/dialog.open
Authorization: Bearer xoxb-such-and-such
Content-type: application/x-www-form-urlencoded
trigger_id=13345224609.738474920.8088930838d88f008e0&dialog=%7B%22callback_id%22%3A%22ryde-46e2b0%22%2C%22title%22%3A%22Request%20a%20Ride%22%2C%22submit_label%22%3A%22Request%22%2C%22notify_on_cancel%22%3Atrue%2C%22state%22%3A%22Limo%22%2C%22elements%22%3A%5B%7B%22type%22%3A%22text%22%2C%22label%22%3A%22Pickup%20Location%22%2C%22name%22%3A%22loc_origin%22%7D%2C%7B%22type%22%3A%22text%22%2C%22label%22%3A%22Dropoff%20Location%22%2C%22name%22%3A%22loc_destination%22%7D%5D%7D
If all is well, you'll get a clean HTTP 200 OK response with an application/json
body declaring:
{
"ok": true
}
If your dialog
parameter or other aspects of your dialog are invalid, detailed errors are provided to help aid you in correcting them. See dialog.open
for full detail on error conditions.
Your dialog is presented to users stylishly with your carefully chosen title
and curated form elements
.
By default, all form elements are required. Use the optional
field to make an element non-mandatory.
Attribute | Type | Description |
---|---|---|
title |
String | User-facing title of this entire dialog. 24 characters to work with and it's required. |
callback_id |
String | An identifier strictly for you to recognize submissions of this particular instance of a dialog. Use something meaningful to your app. 255 characters maximum. Don't use this ID to reference sensitive data; use the more expansive state parameter below for that. Absolutely required. |
elements |
Array | Up to 10 form elements are allowed per dialog. See elements below. Required. |
state |
String | An optional string that will be echoed back to your app when a user interacts with your dialog. Use it as a pointer to reference sensitive data stored elsewhere. |
submit_label |
String | User-facing string for whichever button-like thing submits the form, depending on form factor. Defaults to Submit , localized in whichever language the end user prefers. 48 characters maximum, and may contain only a single word. |
notify_on_cancel |
Boolean | Default is false . When set to true , we'll notify your request URL whenever there's a user-induced dialog cancellation. |
The current list of supported form elements includes:
text
- Text inputs work well with concise free-form answers and inputs with unestablished bounds, such as names, email addresses, or ticket titles if your form is used for something like a bug tracker.textarea
- Text Areas are best when the expected answer is long — over 150 characters or so —. It is best for open-ended and qualitative questions.select
- Select menus are for multiple choice questions, and great for close-ended quantitative questions, such as office locations, priority level, meal preference, etc. The select
elements may contain static menus or dynamically loaded menus specified with an optional data_source
.Text elements are single-line plain text fields.
By default, all fields are required for a user to fill. Otherwise, the client validation will give the user an error. You can also set each field optional ("optional": true
) and in this case, empty fields will submit as null
.
Example:
{
"label": "Email Address",
"name": "email",
"type": "text",
"subtype": "email",
"placeholder": "you@example.com"
}
There is an optional subtype
for the type: text
. The value of the subtype
can be set to either email
, number
, tel
, or url
, where the default is a plain text. Slack will ignore subtype
s that don't match one of those options.
Setting the subtype
is useful for mobile Slack clients where it will trigger special keyboards. For example, when a form field expects a phone number, you should use tel
as a subtype
so it invokes the numeric keypad.
Adding a subtype
does not enforce any validation on the field it is added to.
Element | Type | Description |
---|---|---|
label |
String | Label displayed to user. Required. 48 character maximum. |
name |
String | Name of form element. Required. No more than 300 characters. |
type |
String | The type of form element. For a text input, the type is always text . Required. |
max_length |
Integer | Maximum input length allowed for element. Up to 150 characters. Defaults to 150 . |
min_length |
Integer | Minimum input length allowed for element. Up to 150 characters. Defaults to 0 . |
optional |
Boolean | Provide true when the form element is not required. By default, form elements are required. |
hint |
String | Helpful text provided to assist users in answering a question. Up to 150 characters. |
subtype |
String | A subtype for this text input. Accepts email , number , tel , or url . In some form factors, optimized input is provided for this subtype. |
value |
String | A default value for this field. Up to 150 characters. |
placeholder |
String | A string displayed as needed to help guide users in completing the element. 150 character maximum. |
A textarea
is a multi-line plain text editing control. You've likely encountered these on the world wide web. Use this element if you want a relatively long answer from users. The element UI provides a remaining character count to the max_length
you have set or the default, 3000.
Like text, this element supports subtype values of email
, number
, url
, and tel
.
An example:
{
"label": "Additional information",
"name": "comment",
"type": "textarea",
"hint": "Provide additional information if needed."
}
Attribute |
Type | Description |
---|---|---|
type |
String | For a text area, the type is always textarea . It's required. |
label |
String | Label displayed to user. Required. No more than 48 characters. |
name |
String | Name of form element. Required. No more than 300 characters. |
placeholder |
String | A string displayed as needed to help guide users in completing the element. 150 character maximum. |
max_length |
Integer | Maximum input length allowed for element. 0 -3000 characters. Defaults to 3000. |
min_length |
Integer | Minimum input length allowed for element. 1 -3000 characters. Defaults to 0. |
optional |
Boolean | Provide true when the form element is not required. By default, form elements are required. |
hint |
String | Helpful text provided to assist users in answering a question. Up to 150 characters. |
subtype |
String | A subtype for this text area, just in case you need a lot of space for them. email , number , tel , or url |
value |
String | A default value for this field. Up to 3000 characters. |
Use the select
element for multiple choice selections allowing users to pick a single item from a list. True to web roots, this selection is displayed as a dropdown menu.
A select
element may contain up to 100 selections, provided as an array of hashes (see below) in the form element's options
field, (or an option_groups
array).
These select
elements have a data_source
attribute which specifies whether you want a static list (static
, which is the default) or a dynamic list (see below), but let's take a look at a static
list first:
Example select
form element definition:
{
"label": "Meal preferences",
"type": "select",
"name": "meal_preferences",
"options": [
{
"label": "Vegan",
"value": "vegan"
},
{
"label": "Kosher",
"value": "kosher"
},
{
"label": "Just put it in a burrito",
"value": "burrito"
}
]
}
Example select
form element with option_groups
:
{
"label": "Choose a meme",
"name": "animal",
"type": "select",
"option_groups": [
{
"label": "Cats",
"options": [
{
"label": "Maru",
"value": "maru"
},
{
"label": "Lil Bub",
"value": "lilbub"
},
{
"label": "Hamilton the Hipster Cat",
"value": "hamilton"
}
]
},
{
"label": "Dogs",
"options": [
{
"label": "Boo the Pomeranian",
"value": "boo"
}
]
},
]
}
In addition to the static select menu, you can also generate a data set for a menu on the fly. Make dialog select menus more dynamic by specifying one of these four data_source
types:
Data source type | Description |
---|---|
users |
The element will be populated with options corresponding to the users available to the current user. |
channels |
The element will be populated with options corresponding to the public channels available to the current user. |
conversations |
The element will be populated with options corresponding to the public channels, private channels, DMs, and MPIMs available to the current user. |
external |
The element will be populated with options or options groups return from an endpoint specified in your app configuration setting. |
If no data_source
is specified, it defaults to static
.
Now you can easily populate a select menu with a list of users. For example, when you are creating a bug tracking app, you want to include a field for an assignee. Slack pre-populates the user list in client-side, so your app doesn't need access to a related OAuth scope.
Example select
element with users
data source:
{
"label": "Assignee",
"name": "bug_assignee",
"type": "select",
"data_source": "users"
}
You can also provide a select menu with a list of channels. Specify your data_source
as channels
to limit only to public channels or use conversations to include private channels, direct messages, MPIMs, and whatever else we consider a conversation-like thing.
Example select
element with conversations
data source:
{
"label": "Post this message on",
"name": "channel_notify",
"type": "select",
"data_source": "conversations"
}
A list of options can be loaded from an external URL and used in your dialog menus.
First a little bit of setup is required to configure the URL that the options will be loaded from:
If you've already configured an Options Load URL for other uses, you'll be able to use the type
and callback_id
as below to determine which options data you want to return.
Now you can create a dialog with a select
menu where the data_source
is set to external
:
{
"label": "Bug ticket",
"name": "ticket_list",
"type": "select",
"data_source": "external"
}
As soon as a user clicks or taps the drop-down menu, a request like the following is sent to your specified URL:
{
"type": "dialog_suggestion",
"token": "W3VDvuzi2nRLsiaDOsmJranO",
"action_ts": "1528203589.238335",
"team": {
"id": "T24BK35ML",
"domain": "hooli-hq"
},
"user": {
"id": "U900MV5U7",
"name": "gbelson"
},
"channel": {
"id": "C012AB3CD",
"name": "triage-platform"
},
"name": "external_data",
"value": "",
"callback_id": "bugs"
}
From the external URL, a list of options
(or an option_groups
array) should be returned as a HTTP 200
response:
Example options
from the external data source:
{
"options": [
{
"label": "[UXD-342] The button color should be artichoke green, not jalapeño",
"value": "UXD-342"
},
{
"label": "[FE-459] Remove the marquee tag",
"value": "FE-459"
},
{
"label": "[FE-238] Too many shades of gray in master CSS",
"value": "FE-238"
}
]
}
Example option_groups
from the external data source:
{
"option_groups": [
{
"label": "Visual Design",
"options": [
{
"label": "[UXD-342] The button color should be artichoke green, not jalapeño",
"value": "UXD-342"
}
]
},
{
"label": "Front-End Engineering",
"options": [
{
"label": "[FE-459] Remove the marquee tag",
"value": "FE-459"
},
{
"label": "[FE-238] Too many shades of gray in master CSS",
"value": "FE-238"
}
]
}
]
}
A maximum of 100 options may be included.
Please note that dialog menus uses the more clearly labeled field label
instead of text
for menu option labels.
When you're loading in external objects data for a menu, you can also adjust your code to provide a typeahead style experience where the user types the first few characters of a potential selection, and the app responds with a filtered list of results.
As users type into the select menu, Slack dispatches data to your app and by analyzing their text, you can return the most relevant, filtered options for them. Here's a data payload similar to the one that is sent to your app, showing a situation where the user has typed "des":
{
"type": "dialog_suggestion",
"team": {
"id": "T123ABC456",
"domain": "hooli-hq"
},
"user": {
"id": "U123ABC456",
"name": "sbutterfield"
},
"channel": {
"id": "C123ABC456",
"name": "triage-platform"
},
"action_ts": "1520635427.671963",
"token": "W3VDvuzi2nRLsiaDOsmJranO",
"name": "external_data",
"value": "des",
"callback_id": "bugs"
}
When you're enabling this kind of interaction, it's recommended that you set a min_query_length
attribute to a sane value (at least 2). Otherwise your app might end up searching a massive list of potential matches for a single character, and your DB admins will yell at you.
To set a default selection for a select menu with a data_source
attribute of static
, users
, channels
, or conversations
, provide a value
attribute containing one of the value
attributes from the element's collection of options
:
{
"label": "Meal preferences",
"type": "select",
"name": "meal_preferences",
"value": "vegan",
"options": [
{
"label": "Vegan",
"value": "vegan"
},
{
"label": "Kosher",
"value": "kosher"
},
{
"label": "Just put it in a burrito",
"value": "burrito"
}
]
}
To set a default selection for a select menu with the data_source
type set to external
, instead provide a selected_options
attribute, which should be an array containing a single label
and value
object that you know is in the dynamic options list:
{
"label": "Bug ticket",
"name": "ticket_list",
"type": "select",
"data_source": "external",
"min_query_length": 2,
"selected_options": [
{
"label": "[FE-459] Remove the marquee tag",
"value": "FE-459"
}
]
}
Attribute | Type | Description |
---|---|---|
label |
String | Label displayed to user. Required. No more than 48 characters. |
name |
String | Name of form element. Required. No more than 300 characters. |
type |
String | Set this to select for select elements. |
data_source |
String | Set this to either users , channels , conversations , or external . Default value is static . |
min_query_length |
Number | Specify the number of characters that must be typed by a user into a dynamic select menu before dispatching to the app. |
placeholder |
String | A string displayed as needed to help guide users in completing the element. 150 character maximum. |
optional |
Boolean | Provide true when the form element is not required. By default, form elements are required. |
value |
String | Provides a default selected value for select menus with a data_source of type static , users , channels , or conversations (see above). This option is invalid with data_source of type external , where you must use selected_options as below. |
selected_options |
Array | Provides a default selected value for dynamic select menus with a data_source of type external . This should be an array containing a single object that specifies the default label and value (see above). |
The typical submission workflow is:
callback_id
you set at dialog creation and the values submitted by the user.Upon receiving this payload, your server must respond within 3 seconds, whether the form is valid or not. Otherwise, use the response_url
to POST a delayed response.
Your "Request URL" (formerly known as an "Action URL"), configured in your application management settings under Interactive Components, will receive an interactive framework JSON structure in a URL-encoded payload
POST parameter.
For example, consider this submission:
POST https://example.com/your-request-url
payload=%7B%22type%22%3A%22dialog_submission%22%2C%22submission%22%3A%7B%22name%22%3A%22Sigourney%20Dreamweaver%22%2C%22email%22%3A%22sigdre%40example.com%22%2C%22phone%22%3A%22%2B1%20800-555-1212%22%2C%22meal%22%3A%22burrito%22%2C%22comment%22%3A%22No%20sour%20cream%20please%22%2C%22team_channel%22%3A%22C0LFFBKPB%22%2C%22who_should_sing%22%3A%22U0MJRG1AL%22%7D%2C%22callback_id%22%3A%22employee_offsite_1138b%22%2C%22state%22%3A%22vegetarian%22%2C%22team%22%3A%7B%22id%22%3A%22T1ABCD2E12%22%2C%22domain%22%3A%22coverbands%22%7D%2C%22user%22%3A%7B%22id%22%3A%22W12A3BCDEF%22%2C%22name%22%3A%22dreamweaver%22%7D%2C%22channel%22%3A%7B%22id%22%3A%22C1AB2C3DE%22%2C%22name%22%3A%22coverthon-1999%22%7D%2C%22action_ts%22%3A%22936893340.702759%22%2C%22token%22%3A%22M1AqUUw3FqayAbqNtsGMch72%22%2C%22response_url%22%3A%22https%3A%2F%2Fhooks.slack.com%2Fapp%2FT012AB0A1%2F123456789%2FJpmK0yzoZDeRiqfeduTBYXWQ%22%7D
Decode the payload
parameter's JSON and you have a mapping with a few notable keys:
{
"type": "dialog_submission",
"submission": {
"name": "Sigourney Dreamweaver",
"email": "sigdre@example.com",
"phone": "+1 800-555-1212",
"meal": "burrito",
"comment": "No sour cream please",
"team_channel": "C123ABC456",
"who_should_sing": "U123ABC456"
},
"callback_id": "employee_offsite_1138b",
"state": "vegetarian",
"team": {
"id": "T123ABC456",
"domain": "coverbands"
},
"user": {
"id": "W123ABC456",
"name": "dreamweaver"
},
"channel": {
"id": "C123ABC456",
"name": "coverthon-1999"
},
"action_ts": "936893340.702759",
"token": "M1AqUUw3FqayAbqNtsGMch72",
"response_url": "https://hooks.slack.com/app/T012AB0A1/123456789/JpmK0yzoZDeRiqfeduTBYXWQ"
}
Let's look deeper at those attributes, which you might recognize many of from interactive messages.
type
- to differentiate from other interactive components, look for the string value dialog_submission
.submission
- a hash of key/value pairs representing the user's submission. Each key is a name
field your app provided when composing the form. Each value
is the user's submitted value, or in the case of a static select menu, the value
you assigned to a specific response. The selection from a dynamic menu, the value can be a channel ID, user ID, etc.callback_id
- this value is the unique callback_id
identifier your app gave this instance of the dialog. Use the callback_id
to keep track of which form submission is which, not to store state.state
- this string echoes back what your app passed to dialog.open
. Use it as a pointer that references sensitive data stored elsewhere.team
- this hash contains the id
and name
of the workspace from which this interaction occurreduser
- this hash contains the id
and name
of the user who completed the formchannel
- this hash contains the id
and name
of the channel or conversation where this dialog was completedaction_ts
- this is a unique identifier for this specific action occurrence generated by Slack. It can be evaluated as a timestamp with milliseconds if that is helpful to you.token
- this is a deprecated verification token shared between your app and Slack, used to check that an incoming request originates from Slack.response_url
- the URL can be used to post responses to dialog submissions. Read our guide to app interactivity to learn more about how to respond using a response_url
.The token
value, which represents a verification token, is now deprecated. The best way to verify the authenticity of a Slack request is to use the signing secret provided to your app.
state
to pass extra information through dialogs When your app calls dialog.open
, it may optionally pass additional data via the state
parameter. The state
string may be up to 3,000 characters long, and it isn't shown to users. During dialog submission and cancellation, the state
string is echoed back to your app. Whatever stash of pointers you passed during dialog.open
gets returned to you, unharmed and unchanged.
Note: don't store sensitive information in the state
field. It's best to use state
to reference sensitive data stored elsewhere. You may already be using the callback_id
parameter for that, but we strongly recommend using the state
field instead.
While Slack will handle some client-side validation of user input upon submission, we encourage your app to do its own round of validation based on its own business logic.
As soon as your user hits the submit button, Slack client will validate the user's inputs against the validation parameters that you have passed to make sure that all the required fields are filled and the formats are correct. And the form won't submit until the user corrects all errors.
You should validate the submission
values you receive server-side against your own heuristics.
If your app finds any errors with the submission, respond with an application/json
payload within the body of a 200 OK
response - the requests between your app and Slack are still OK
after all, so don't use any kind of error response.
This payload should be an errors
array containing 1 or more objects that include:
name
- a string which specifies the corresponding dialog element that is being rejected. This must match the name
used to create that element.error
- a string which describes why that element is being rejected.Here's an example of what that payload should look like:
{
"errors": [
{
"name": "email_address",
"error": "Sorry, this email domain is not authorized!"
},
{
"name": "username",
"error": "Uh-oh. This username has been taken!"
}
]
}
The API returns these errors to the user in-app, allowing the user to make corrections and submit again.
When there are no exceptions within the dialog submission, your app must respond with 200 OK
with an empty body. This will complete the dialog.
After you've confirmed the submission is valid and sent a HTTP 200 OK
message, you'll want to let the user know everything is fine.
Use a method like chat.postMessage
or chat.postEphemeral
, depending on context and desired visibility, to create a message thanking the user and/or providing other feedback. You can also send a delayed response to the response_url
if you need more than 3 seconds to respond. with the response_url
, your app can continue interacting with users up to 5 times within 30 minutes of the action invocation.
For example, if you are building an app for survey, it is still a good idea to send a follow-up message to make sure your valuable user knows the form submission was successful!
Read our guide to app interactivity to learn more about sending responses.
When users dismiss a dialog by either clicking on the "Cancel" button, exit "x" on the top-right corner, or by clicking away from a dialog, we'll warn them that they'll lose any answers they've made to an unsubmitted dialog.
Once the dialog is canceled, Slack can send you a dialog_cancellation
events to your Request URL, if you wish. To receive the notification, set the notify_on_cancel
value true
, when you open the dialog.
If you wish to follow up with the user, use the cancellation's response_url
to create a new message using response URL semantics.
{
"type": "dialog_cancellation",
"token": "old-and-moldy-verification-token",
"action_ts": "1542993577.333025",
"team": {
"id": "T123ABC456",
"domain": "coverbands"
},
"user": {
"id": "U123ABC456",
"name": "leepresson"
},
"channel": {
"id": "C123ABC456",
"name": "graceland"
},
"callback_id": "best_elvis_impersonator_name",
"response_url": "https://hooks.slack.com/app/T123ABC456/486xxxxxx/jbF9HF",
"state": "final_round"
}
Existing workflows using only conversation, message buttons, or message menus can be enhanced with the focused concentration made possible with dialogs.
Imagine a /helpdesk
slash command connected to a company's internal IT helpdesk. With very limited syntax enforcement and the wild possibilities inherent in free-form text, filing a ticket is imprecise and less instantly actionable.
/helpdesk hardware "help my cat chewed on my mouse cable it doesn't work anymore"
Commands like this are noble in purpose but could be made more precise in execution with dialogs.
Your software could easily interpret this as a ticket meant for a hardware
category. With some heuristics and analysis, your app might derive that it's about a mouse.
Without asking a series of focused questions to illuminate the entire surface area of the user's inquiry, the user's submission is significantly less actionable than its potential.
By invoking a dialog, you may ask specific guided questions around urgency, platform, location, and other nuances made possible with multiple choice.
Another example, illustrated in the animation below, demonstrates a slash command execution leading to an optimized dialog and useful outcome.
In general, the easier it is to enter information into a dialog, the more likely your users are to fill them out to completion. Wherever possible, favor structured inputs over freeform text, and work to keep the total length relatively short.
In order to look best on mobile as well as desktop, we suggest that modal titles be short. Our tips on choosing words for messages generally apply: keep modal titles sentence-cased; pick action verbs for buttons that confirm what the user is doing.
Provide a placeholder
value for all field elements to better communicate purpose independent of the user's interface.
These are best used for concise answers with established bounds or options, e.g. office location, age range, or dietary preference. Keep dropdown options short, and remember to test how they render on mobile devices.
Text input fields are capped at 150 characters, and are best used for concise freeform answers, like name or ticket title.
If inputs are better served with pre-selected answers (e.g. age ranges, department), consider using a dropdown. If you expect input to be longer than 150 characters, consider using a text area.
Text areas are good for open-ended questions that need more room, like meeting notes or interview feedback. Most dialogs should not have more than one or two text areas; remember that keeping the input brief and contextual will help ensure that people complete the forms.
Like this:
Not like this:
Your dialogs can be short and to the point, a focused way to collect a single piece of information. They can be long, asking questions requiring more thought, research, and careful response. Chain dialogs together with buttons or menus to serialize phased workflow execution.