In this tutorial, you'll learn how to usethe built-in forms in yourSlack's next-generation platform apps.
The next-gen platform offers a simple form feature, which is available as a built-inSchema.slack.functions.OpenForm
function.
After reading this tutorial, you will become a master of the built-in forms 🚀
Prerequisites
If you're new to the platform, please read myThe Simplest "Hello World" tutorial first. In a nutshell, you'll need a paid Slack workspace, and permission to use the beta feature in the workspace. And then, you can connect your Slack CLI with the workspace.
If all the above are already done, you're ready to build your first app. Let's get started!
Create a Blank Project
When you start a new project, you can runslack create
command. In this tutorial, you will build an app from scratch. So select "Blank project" from the list:
$slack create? Select a template to build from: Hello World A simple workflow that sends a greeting Scaffolded project A solid foundational project that uses a Slack datastore> Blank project A, well.. blank project To see all available samples, visit github.com/slack-samples.
Once the project is generated, let's check ifslack run
command works without any issues. This command installs a "dev" version of your new app into your connected Slack workspace. Now your app's bot user is in the workspace, and your app has its bot token for API calls.
$cdfrosty-mink-263$slack run? Choose a workspace seratch T03E94MJU App is not installed to this workspaceUpdating dev appinstallforworkspace"Acme Corp"⚠️ Outgoing domains No allowed outgoing domains are configured If yourfunctionmakes network requests, you will need to allow the outgoing domains Learn more about upcoming changes to outgoing domains: https://api.slack.com/future/changelog✨ seratch of Acme CorpConnected, awaiting events
If you seeConnected, awaiting events
log message, the app is successfully connected to Slack. You can hit "Ctrl + C" to terminate the local app process.
Define Workflow and Trigger
Let's start with defining a simple demo workflow and its link trigger. To use the built-in forms in a simple way,you must use a link trigger. TheOpenForm
function needs theinteractivity (Schema.slack.types.interactivity)
input parameter to continue direct interactions with the end-user. As of this writing, only link triggers supply this input value to a workflow and its functions.
Alternatively, you can use buttons/select menus in a channel message to generateinteractivity
in the middle of a workflow. In this case, you can useOpenForm
as the succeeding function. I won't cover this topic here, but I will publish a different tutorial on the topic soon!
Let's define an empty workflow and its link trigger as below. As always, save the source code asworkflow_and_trigger.ts
:
// ----------------// Workflow Definition// ----------------import{DefineWorkflow,Schema}from"deno-slack-sdk/mod.ts";exportconstworkflow=DefineWorkflow({callback_id:"form-demo-workflow",title:"OpenForm Demo Workflow",input_parameters:{properties:{interactivity:{type:Schema.slack.types.interactivity},user_id:{type:Schema.slack.types.user_id},channel_id:{type:Schema.slack.types.channel_id},},required:["interactivity","user_id","channel_id"],},});// TODO: Add a step using the built-in form here// TODO: Confirm the outputs from the above OpenForm function// ----------------// Trigger Definition// ----------------import{Trigger}from"deno-slack-api/types.ts";consttrigger:Trigger<typeofworkflow.definition>={type:"shortcut",name:"Form Demo Trigger",workflow:`#/workflows/${workflow.definition.callback_id}`,inputs:{// interactivity is necessary for using OpenForm functioninteractivity:{value:"{{data.interactivity}}"},// The following inputs are not necessary for OpenForm// You'll use this just for the succeeding functions,// which confirm the outputs of OpenFormuser_id:{value:"{{data.user_id}}"},channel_id:{value:"{{data.channel_id}}"},},};exportdefaulttrigger;
And then, add the workflow tomanifest.ts
:
import{Manifest}from"deno-slack-sdk/mod.ts";// Add thisimport{workflowasDemoWorkflow}from"./workflow_and_trigger.ts";exportdefaultManifest({name:"frosty-mink-263",description:"Demo workflow",icon:"assets/default_new_app_icon.png",workflows:[DemoWorkflow],// Add thisoutgoingDomains:[],botScopes:["commands","chat:write","chat:write.public"],});
Create a Link Trigger
Next, you'll use two terminal windows. One forslack run
command and another forslack triggers create
command.
To register the workflow, runslack run
command on the first terminal window. And then, runslack triggers create --trigger-def workflow_and_trigger.ts
on another one. You will see the following outputs:
$slack triggers create--trigger-def workflow_and_trigger.ts? Choose an app seratch(dev) T03E94MJU frosty-mink-263(dev) A04G9S43G2K⚡ Trigger created Trigger ID: Ft04HGLH426L Trigger Type: shortcut Trigger Name: Form Demo Trigger URL: https://slack.com/shortcuts/***/***
As we learned inthe first tutorial, share the link trigger URL in a public channel in the connected Slack workspace. OK, the trigger is ready to use. Let's go back to coding.
Add OpenForm Function to the Workflow
Add the following two function steps to the workflow you just defined:
// Step using the built-in formconstformStep=workflow.addStep(Schema.slack.functions.OpenForm,{title:"Send a greeting",interactivity:workflow.inputs.interactivity,submit_label:"Send greeting",fields:{// fields.elements will be converted to Block Kit components under the hoodelements:[{name:"recipient",title:"Recipient",type:Schema.slack.types.user_id,// => "users_select"default:workflow.inputs.user_id,},{name:"channel",title:"Channel to send message to",type:Schema.slack.types.channel_id,// => "channels_select"default:workflow.inputs.channel_id,},{name:"message",title:"Message to recipient",type:Schema.types.string,// => "plain_text_input"long:true,// => multiline: true},],required:["recipient","channel","message"],},});// Confirm the outputs from the above OpenForm functionworkflow.addStep(Schema.slack.functions.SendEphemeralMessage,{// The name of the element will be the key to access the valueuser_id:formStep.outputs.fields.recipient,channel_id:formStep.outputs.fields.channel,message:"OpenForm's `outputs.fields`: `"+formStep.outputs.fields+"`",});
You may not be familiar withBlock Kit, Slack's UI framework. With Block Kit, you can build a rich user interface just by defining the UI in pre-defined JSON data format. The same Block Kit UI works nicely for desktop apps, web browsers, and mobile apps (iOS, iPadOS, Android).
TheOpenForm
function offers a much simpler version of the UI definition. When you define the modal UI, theOpenForm
function generates equivalent Block Kit components under the hood.
If you're interested in using Block Kit directly, I will publish a different tutorial on it. Stay tuned!
Run The Workflow
Let's run the workflow. When you run the workflow, the app opens a popup modal dialog to receive your inputs and then posts an ephemeral message (a message visible only to you) with the outputs ofOpenForm
:
More Form Options
As you can see inthe document, the basic properties of each element in the form arename
,title
,type
,description
, anddefault
. Usually, the minimum set of properties would bename
,title
, andtype
. Let me share as many examples as possible below:
Required Inputs
In the above example, therequired
list is["recipient", "channel", "message"]
. This means that these three inputs must be provided when submitting the form. You can add any of thename
s offields.elements
to the list.
Text Input Element
The simple text input form element looks like the below. The type must beSchema.types.string
. With this type,OpenForm
generates aplain_text_input
block element for you.
{name:"message",// unique key for this elementtitle:"Message to recipient",// Label on the UItype:Schema.types.string,// => "plain_text_input"},
To allow multi-line inputs, you can addlong: true
property. Also, to set input validations on the input lengths, you can useminLength
andmaxLength
.
{name:"message",title:"Message to recipient",type:Schema.types.string,long:true,// => multiline: trueminLength:5,// inclusivemaxLength:20,// inclusive},
Another option to validate the text input isformat
. To verify the format, you can set eitheremail
orurl
.
{name:"contact",title:"Your Email Address",type:Schema.types.string,format:"email",},
Static Select Menu
WithSchema.types.string
type, you can use a select menu with static option items.
{name:"favorite",title:"Favorite",type:Schema.types.string,choices:[{value:"dog",title:"Dog"},{value:"cat",title:"Cat"},],enum:["dog","cat"],default:"cat",},
The above example can look like the following:
Since theenum
property is not used for the UI representation, you may wonder if it can be omitted. But it's still required. If you remove it, the element falls back to the simple text input element, and thechoices
won't be used at all.
Channel/User Select Menu
When you setuser_id
to thetype
of an element, the element will be ausers_select
select menu element.
{name:"recipient",title:"Recipient",type:Schema.slack.types.user_id,// => "users_select"},
Similarly, when settingchannel_id
, the element will be achannels_select
select menu element.
{name:"channel",title:"Channel to send message to",type:Schema.slack.types.channel_id,// => "channels_select"},
Multi-select Menu
Block Kit supportsmulti-select menu elements. To add such elements, you can useSchema.types.array
fortype
along with the supported type (e.g.,Schema.slack.types.user_id
) foritems.type
.
The following example will be amulti_users_select
select menu element.
{name:"people",title:"People",type:Schema.types.array,// => multi-select// The type of the array itemitems:{type:Schema.slack.types.user_id},// => "multi_users_select"default:["U12345","U23456"],},
Full Example Form
There are so many options! So, instead of writing a lengthy tutorial, I've built a form with all the possible elements:
{name:"recipient",title:"Recipient",type:Schema.slack.types.user_id,// => "users_select"default:workflow.inputs.user_id,},{name:"channel",title:"Channel to send message to",type:Schema.slack.types.channel_id,// => "channels_select"default:workflow.inputs.channel_id,},{name:"message",title:"Message to recipient",type:Schema.types.string,// => "plain_text_input"long:true,// => multiline: trueminLength:1,// inclusivemaxLength:100,// inclusive},{name:"favorite_animal",title:"Favorite Animal",type:Schema.types.string,// => "static_select"choices:[{value:"dog",title:"Dog"},{value:"cat",title:"Cat"},],enum:["dog","cat"],default:"cat",},{name:"favorite_animals",title:"Favorite Animals",type:Schema.types.array,// => "mutli_static_select"items:{type:Schema.types.string,choices:[{value:"dog",title:"Dog"},{value:"cat",title:"Cat"},],enum:["dog","cat"],},maxItems:2,default:["cat"],},{name:"contact",title:"Your Email Address",type:Schema.types.string,format:"email",// => "email_text_input"},{name:"channels",title:"Favorite Channels",type:Schema.types.array,// => "multi_channels_select"items:{type:Schema.slack.types.channel_id},},{name:"team_members",title:"Team Members",type:Schema.types.array,// => "multi_users_select"items:{type:Schema.slack.types.user_id},},{name:"approved",title:"Already Approved by My Manager",type:Schema.types.boolean,// => "checkboxes"},{name:"count",title:"Count",type:Schema.types.integer,// => "number_input" with is_decimal_allowed: false},{name:"amount",title:"Amount",type:Schema.types.number,// => "number_input"},{name:"due_date",title:"Due Date",type:Schema.slack.types.date,// => "datepicker"},{name:"due_time",title:"Due Date Time",type:Schema.slack.types.timestamp,// => "datepicker" + "timepicker"},{name:"rich_text",title:"Rich Text Input",type:Schema.slack.types.rich_text,},
The very long form looks like the below:
Wrapping Up
You've learned the following points with this hands-on tutorial:
- Define a built-in form with various elements
The complete project is available athttps://github.com/seratch/slack-next-generation-platform-tutorials/tree/main/07_Built-in_Forms
I hope you enjoy this tutorial! As always, if you have any comments or feedback, please feel free to let me know on Twitter (@seratch) or elsewhere I can check out!
Happy hacking with Slack's next-generation platform 🚀
Top comments(0)
For further actions, you may consider blocking this person and/orreporting abuse