Block Actions
Overview
If you send a message with BlockKit components, you can trigger a workflow when a user interacts with those components. For example, you can trigger a workflow when a user clicks a button, selects an option from a menu, or submits a modal.
The event will be the block_action event payload from Slack, which includes the actions
array. You can use the actions
array to determine which action was triggered, and the block_id
and action_id
to determine which component was interacted with.
A very simple example would be to first send a message to a channel with a button, and then trigger a workflow when the button is clicked:
import * as slack from "@trigger.dev/slack";
import { z } from "zod";
const BLOCK_ID = "employee-ping";
new Trigger({
id: "send-message-with-button",
name: "Send Message with Button",
on: scheduleEvent({
rateOf: {
minutes: 5,
},
}),
run: async (event, ctx) => {
await slack.postMessage("Are you still there?", {
channelName: "employee-ping",
//text appears in Slack notifications on mobile/desktop
text: "Are you still there?",
blocks: [
{
type: "section",
text: {
type: "mrkdwn",
text: "Are you still there?",
verbatim: true,
},
},
{
type: "actions",
block_id: BLOCK_ID, // this is the block_id that we'll use to identify the message
elements: [
{
type: "button",
action_id: "nope",
text: {
type: "plain_text",
text: "I'm at lunch",
emoji: true,
},
value: "lunch",
},
{
type: "button",
action_id: "youbet",
text: {
type: "plain_text",
text: "Still here!",
emoji: true,
},
value: "in-my-seat",
},
],
},
],
});
},
}).listen();
Passing custom data
There are three ways to pass custom data to the workflow that is triggered by the event:
- Use the
value
field of the BlockKit component. This is the easiest way to pass data, but it is limited to 2000 characters. - Use the
metadata
option when sending the message. This is best for handling “context” data that relates to any possible action taken in a BlockKit message.
An example of using the value
field:
await slack.postMessage("New Issue", {
channelName: "github-issues",
//text appears in Slack notifications on mobile/desktop
text: "There is a new GitHub issue in the repo",
blocks: [
{
type: "actions",
block_id: "new.issue", // this is the block_id that we'll use to identify the message
elements: [
{
type: "button",
action_id: "reply",
text: {
type: "plain_text",
text: "Reply to Issue",
},
value: githubIssueId,
},
{
type: "button",
action_id: "close",
text: {
type: "plain_text",
text: "Close Issue",
},
value: githubIssueId,
},
],
},
],
});
And an example using the metadata
option (which can be any JSON-serializable data):
await slack.postMessage("New Issue", {
channelName: "github-issues",
//text appears in Slack notifications on mobile/desktop
text: "There is a new GitHub issue in the repo",
metadata: { githubIssueId },
blocks: [
{
type: "actions",
block_id: "new.issue", // this is the block_id that we'll use to identify the message
elements: [
{
type: "button",
action_id: "reply",
text: {
type: "plain_text",
text: "Reply to Issue",
},
value: "reply",
},
{
type: "button",
action_id: "close",
text: {
type: "plain_text",
text: "Close Issue",
},
value: "close",
},
],
},
],
});
JSX Slack
You can use the JSX Slack project to build your BlockKit messages and trigger the blockActionInteraction
event.
Step 1: Install and configure JSX Slack
npm
pnpm
yarn
npm install jsx-slack
If you aren’t already using React in your project, you will need to update your tsconfig.json
file to add the compilerOptions.jsx
option, and ensure to include .tsx
files in your include
array:
{
"compilerOptions": {
"jsx": "react-jsx"
},
"include": ["src/**/*.ts", "src/**/*.tsx"]
}
Step 2: Create your BlockKit message
/** @jsxImportSource jsx-slack */
import JSXSlack, {
Actions,
Blocks,
Button,
Section,
Select,
Option,
} from "jsx-slack";
export function progressBlock(blockId: string) {
return JSXSlack(
<Blocks>
<Section>How is your progress today?</Section>
<Actions blockId={blockId}>
<Button value="blocked" actionId="status-blocked">
I'm blocked
</Button>
<Button
value="help"
actionId="status-help"
url="https://xkcd.com/1349/"
>
Get help
</Button>
<Select actionId="rating" placeholder="Rate it!">
<Option value="5">5 {":star:".repeat(5)}</Option>
<Option value="4">4 {":star:".repeat(4)}</Option>
<Option value="3">3 {":star:".repeat(3)}</Option>
<Option value="2">2 {":star:".repeat(2)}</Option>
<Option value="1">1 {":star:".repeat(1)}</Option>
</Select>
</Actions>
</Blocks>
);
}
Please note, that to use jsx-slack
you will need to add the jsxImportSource
pragma to the top of your file. This is because jsx-slack
is not a React library, but it uses the same syntax as React. The file also needs to be a .jsx
or .tsx
file (like when you use React).
Step 3: Use your BlockKit message in a postMessage
call
import * as slack from "@trigger.dev/slack";
import { z } from "zod";
import { progressBlock } from "./messages";
const BLOCK_ID = "issue.action.block";
//1. every minute see how your employees are doing, we don't recommend this frequency 😉
new Trigger({
id: "slack-interactivity",
name: "Testing Slack Interactivity",
on: scheduleEvent({
rateOf: {
minutes: 1,
},
}),
run: async (event, ctx) => {
await slack.postMessage("jsx-test", {
channelName: "employee-progress",
text: "How is your progress today?",
blocks: progressBlock(BLOCK_ID), // Pass in the block_id which we'll trigger on in the next step
});
},
}).listen();
Params
The block_id
of the BlockKit component that you want to listen for.
The action_id
of the BlockKit component that you want to listen for. If you
don’t specify an actionId
, the workflow will be triggered for any action on
the specified blockId
. You can also specify an array of action_id
s to
listen for multiple actions.
Event Payload
Please see the Slack Block Actions event payload for more information.
The type of event. This will always be block_actions
.
A short-lived ID that can be used to open a modal. See the openView docs
A short-lived URL that can be used to send a response to the user. See the postMessageResponse docs for more information.
The user that triggered the event.
The message that the user interacted with.
The view that the user interacted with.
An array of actions that the user interacted with. actions.action_id
can be
used to determine which action was triggered. (e.g. which button was clicked)
The team that the user is a part of.
The channel where the interaction took place.