The new Slack platform and the features described below are in beta and under active development.


Build seamless data collection into your next-generation Slack app with forms, where information collected from a user can be mapped to the inputs of workflow steps.

If you're new to using forms, keep reading! If you're interested in modifying existing forms, jump ahead to the schema of form field elements.

Collecting input in a workflow

Let's dive into how to add the OpenForm built-in function to a workflow! Familiarizing yourself with our functions and workflows guides before continuing will help you ease into adding interactivity into your workflow.

1. Add interactivity to your workflow

First things first, let's take a look at the "Send a Greeting" workflow that comes with the Hello World sample app, available to you when you create a new Slack app.

Making your app interactive is the key to collecting user data. To accomplish this, an interactivity input parameter must be included as a workflow property in the workflow definition.

// workflows/greeting_workflow.ts
import { DefineWorkflow, Schema } from "deno-slack-sdk/mod.ts";

const GreetingWorkflow = DefineWorkflow({
  callback_id: "greeting_workflow",
  title: "Send a greeting",
  description: "Send a greeting to channel",
  input_parameters: {
    properties: {
      interactivity: {
        type: Schema.slack.types.interactivity,
      channel: {
        type: Schema.slack.types.channel_id,
    required: ["interactivity"],

Learn more about the interactivity type in our built-in types guide.

2. Add a form to your workflow

Fantastic, you've completed adding the interactivity property into your workflow. Now it's time to add OpenForm as a step in your workflow.

A workflow is a multi-step process, where some of the steps are automated; adding steps to your workflows are what makes your app so seamless. For example, say you need to collect user data, send it to your information systems, then update a Slack channel with a link to a report. Each task will need to be configured as a step in your workflow, allowing for user interactivity data to be passed to each step sequentially until this process is complete.

While some functions you use within your workflow will be custom functions, Slack has a library of built-in functions that cover some of the most common tasks executed on our platform.

The OpenForm built-in function allows for the collection of user input which can be used when executing follow-on steps in a workflow like sending messages, creating channels, or even pinning a message in a channel.

Add the OpenForm function as a step in your workflow:

// workflows/greeting_workflow.ts

const inputForm = GreetingWorkflow.addStep(
    title: "Send message to channel",
    description: "This form sends a message to a channel. Practice with the <|Hello World> tutorial", // Description of the form
    interactivity: GreetingWorkflow.inputs.interactivity,
    submit_label: "Send message", // The text that will show as the button label in your app
    fields: {
      elements: [{
        name: "channel",
        title: "Channel to send message to",
        type: Schema.slack.types.channel_id,
      }, {
        name: "message",
        title: "Message",
        type: Schema.types.string,
        long: true,
      required: ["channel", "message"],

// Add an extra step and send a message to a channel using user input
GreetingWorkflow.addStep(Schema.slack.functions.SendMessage, {
  message: inputForm.outputs.fields.message,

export default GreetingWorkflow;

Notice that you can include a top-level link description in the form, as included in line seven above. Linking is only supported in the form description, however, not the element description.

The fields of a form are made up of different types of elements that follow a certain schema. The type of each element determines the input type, and includes types such as string, boolean, timestamp, channel_id, and user_id.

Forms haves two output parameters:

  • user_id: User ID of the person who filled out the form
  • fields: The same field names in the inputs that are returned as outputs with the values as those entered by the user

Output parameters store user interactivity data and can be used to pass information to follow-on steps in the workflow.

The example above included an extra step: sending the users message to a specific channel that the user specified. Using the output parameter fields and selecting the desired output element by name i.e channel and message, the user's input data was passed into the second step of the workflow.

Add as first step in workflow
When using the OpenForm built-in function, it must be added as the first step in your workflow.

3. Manifest and deploy your workflow

With a workflow defined and steps outlined, it's time to make this an official part of your app! By adding the workflow definition to your manifest and then deploying your app, this new workflow can find a place in your workspace.

A manifest containing your newfound workflow will have the following additions:

// manifest.ts
import GreetingWorkflow from "./workflows/greeting_workflow.ts"; // First, import the new workflow into the manifest file

export default Manifest({
  name: "Workflow Messages",
  description: "A simple way to share thoughts",
  icon: "assets/icon.png",
  workflows: [GreetingWorkflow], // Then, add the newly imported workflow to your manifest here
  outgoingDomains: [],
  botScopes: ["commands", "chat:write", "chat:write.public"],

After updating the manifest, these changes can be deployed to a workspace using slack deploy!

4. Open an entry point with a trigger

Let's add some momentum behind your workflow and create a Link trigger using a trigger file. In the trigger definition, add interactivity as an input value; this value holds context about the user interactivity that triggered the trigger and passes it along to your workflow.

In a separate file, define your trigger in the following way:

// triggers/greeting_trigger.ts
import { Trigger } from "deno-slack-api/types.ts";
import GreetingWorkflow from "./workflows/greeting_workflow.ts";

const greetingTrigger: Trigger<typeof GreetingWorkflow.definition> = {
  type: "shortcut",
  name: "Send a greeting",
  description: "Send greeting to channel",
  workflow: "#/workflows/greeting_workflow",
  inputs: {
    interactivity: {
      value: "{{data.interactivity}}",
    channel: {
      value: "{{data.channel_id}}",

export default greetingTrigger;

Run the following command to create the trigger in your CLI:

# create a trigger with the callback_id of your workflow and the trigger file
$ slack trigger create --trigger-def triggers/greeting_trigger.ts


⚡ Trigger created
   Trigger ID:   Ft024ABCD12X
   Trigger Type: shortcut
   Trigger Name: Send a greeting

Viola! You now have a shortcut URL to share in a channel or save as a bookmark! This URL acts as an entry point into your workflow, kicking things off with the form created back in Step 2 when clicked.

Next, learn about the different field elements of a form below.

Form field element schema

Form elements have several properties you can customize depending on the element type:

Property Type Description
name String (required) The internal name of the element
title String The label for the form element that the user sees. Maximum length is 25 characters
type Schema.slack.types.* The type of form element to display
description String (optional) The description of the form element
default Same type as type (optional) Default value for this field

For example, here is a form that collects a channel_id, a user_id, a number, and a date:

const inputForm = LogRunWorkflow.addStep(
    title: "Log your run",
    interactivity: LogRunWorkflow.inputs.interactivity,
    submit_label: "Submit run",
    fields: {
      elements: [{
        name: "channel",
        title: "Channel to send to",
        type: Schema.slack.types.channel_id,
      }, {
        name: "runner",
        title: "Runner",
        type: Schema.slack.types.user_id,
      }, {
        name: "distance",
        title: "Distance (in miles)",
        type: Schema.types.number,
      }, {
        name: "rundate",
        title: "Run date",
      required: ["channel", "runner", "distance", "rundate"],

Form field element type parameters

The following parameters are available for each type when defining your form. Please note that some element types are prefixed with Schema.types, while some are prefixed with Schema.slack.types:

Type Parameters Notes
Schema.types.string title, description, default, minLength, maxLength, format, enum, choices, long, type If the long parameter is provided and set to true, it will render as a multi-line text box. Otherwise, it renders as a single-line text input field. In addition, basic input validation can be done by setting format to either email or url
Schema.types.boolean title, description, default, type A boolean rendered as a checkbox in the form
Schema.types.integer title, description, default, enum, choices, type, minimum, maximum A whole number, such as -1, 0, or 31415926535
Schema.types.number title, description, default, enum, choices, type, minimum, maximum A number that allows decimal points, such as 13557523.0005
Schema.types.array title, description, default, type, items, maxItems For the items parameter, Schema.types.string, Schema.slack.types.channel_id, and Schema.slack.types.user_id are supported. For Schema.types.string only, you can also specify enum and choices within the items type. maxItems allows you to specify the maximum number of items that can be selected. default must also be an array, or its values will be ignored title, description, default, enum, choices, type A string containing a date, displayed in YYYY-MM-DD format
Schema.slack.types.timestamp title, description, default, enum, choices, type A Unix timestamp, rendered as a date picker
Schema.slack.types.user_id title, description, default, enum, choices, type A user picker
Schema.slack.types.channel_id title, description, default, enum, choices, type A channel picker
Schema.slack.types.rich_text title, description, default, type A way to nicely format messages in your app. Note that this type cannot be converted to other message types, such as a string

For each parameter listed above, type is required. For arrays, items is also required.

The following is an example array containing Schema.types.string types:

          name: "departments",
          title: "Your department",
          type: Schema.types.array,
          description: "You belong here.",
          items: {
            type: Schema.types.string,
            enum: ["marketing", "design", "sales", "engineering"],
          default: ["sales", "engineering"]

The enum and choices parameters should be provided together. They are used to create a drop-down that allows users to select an item from a list. For example:

const teammate = NewMemberIntake.addStep(
    title: "Welcome to the team!",
    interactivity: NewMemberIntake.inputs.interactivity,
    submit_label: "Join",
    description: "There's a place for you here.",
    fields: {
      elements: [{
        name: "department",
        title: "What department are you in?",
        type: Schema.types.string,
        enum: ["Marketing", "Design", "Sales", "Engineering"],
        choices: [
          { value: "marketing", title: "Marketing", description: "Share the excitement"},
          { value: "design", title: "Design", description: "Create wonderful experiences" },
          { value: "sales", title: "Sales", description: "Solve problems with customers" },
          { value: "engineering", title: "Engineering", description: "Build systems for solutions" },
      required: ["department"],

Keep the curiosity flowing and check out our Block Kit Interactivity guide next, which covers bringing interactivity to custom functions!

Have 2 minutes to provide some feedback?

We'd love to hear about your experience with the new Slack platform. Please complete our short survey so we can use your feedback to improve.