UNPKG

chat

Version:

Unified chat abstraction for Slack, Teams, Google Chat, and Discord

150 lines (119 loc) 4.74 kB
--- title: Actions description: Handle button clicks and interactive card events across platforms. type: guide prerequisites: - /docs/cards related: - /docs/modals --- Actions let you handle button clicks, dropdown selections, and other interactive events from [cards](/docs/cards). Register handlers with `onAction` to respond when users interact with your cards. ## Handle a specific action ```typescript title="lib/bot.ts" lineNumbers bot.onAction("approve", async (event) => { await event.thread.post(`Order approved by ${event.user.fullName}!`); }); ``` ## Handle multiple actions ```typescript title="lib/bot.ts" lineNumbers bot.onAction(["approve", "reject"], async (event) => { const action = event.actionId === "approve" ? "approved" : "rejected"; await event.thread.post(`Order ${action} by ${event.user.fullName}`); }); ``` ## Catch-all handler Register a handler without an action ID to catch all actions: ```typescript title="lib/bot.ts" lineNumbers bot.onAction(async (event) => { console.log(`Action: ${event.actionId}, Value: ${event.value}`); }); ``` ## ActionEvent The `event` object passed to action handlers: | Property | Type | Description | |----------|------|-------------| | `actionId` | `string` | The `id` from the Button or Select component | | `value` | `string` (optional) | The `value` from the Button or selected option | | `user` | `Author` | The user who clicked | | `thread` | `Thread \| null` | The thread containing the card (null for view-based actions like home tab buttons) | | `messageId` | `string` | The message containing the card | | `threadId` | `string` | Thread ID | | `adapter` | `Adapter` | The platform adapter | | `triggerId` | `string` (optional) | Platform trigger ID (used for opening modals) | | `openModal` | `(modal) => Promise<void>` | Open a modal dialog | | `raw` | `unknown` | Platform-specific event payload | ## Pass data with buttons Use the `value` prop on buttons to pass extra context to your handler: ```tsx title="lib/bot.tsx" <Button id="report" value="bug">Report Bug</Button> <Button id="report" value="feature">Request Feature</Button> ``` ```typescript title="lib/bot.ts" lineNumbers bot.onAction("report", async (event) => { if (event.value === "bug") { // Open bug report flow } else if (event.value === "feature") { // Open feature request flow } }); ``` ## Open a modal from an action Use `event.openModal()` to open a [modal](/docs/modals) in response to a button click: ```tsx title="lib/bot.tsx" lineNumbers import { Modal, TextInput, Select, SelectOption } from "chat"; bot.onAction("feedback", async (event) => { await event.openModal( <Modal callbackId="feedback_form" title="Send Feedback" submitLabel="Send"> <TextInput id="message" label="Your Feedback" multiline /> <Select id="category" label="Category"> <SelectOption label="Bug" value="bug" /> <SelectOption label="Feature" value="feature" /> </Select> </Modal> ); }); ``` <Callout type="info"> Modals are currently supported on Slack and Teams. Other platforms will receive a no-op or fallback behavior. </Callout> ## Callback URLs Buttons accept a `callbackUrl` prop. When clicked, the action data is POSTed to that URL in addition to firing any `onAction` handler. This pairs naturally with webhook-based workflow engines to build approval flows without any `onAction` handler at all: ```tsx title="lib/bot.tsx" lineNumbers bot.onNewMention(async (thread) => { const approveUrl = "https://example.com/webhook/approve"; const denyUrl = "https://example.com/webhook/deny"; await thread.post( <Card title="Deploy v2.4.1?"> <Actions> <Button callbackUrl={approveUrl} id="approve" style="primary"> Approve </Button> <Button callbackUrl={denyUrl} id="deny" style="danger"> Deny </Button> </Actions> </Card> ); }); ``` ### Callback payload The POST body sent to the `callbackUrl`: ```json { "type": "action", "actionId": "approve", "user": { "id": "U123", "name": "alice" }, "threadId": "slack:C123:1234567890.123", "messageId": "1234567890.456" } ``` If the button also has a `value` prop, it is included in the payload as `"value"`. <Callout type="info"> Platform limits apply to encoded button data. Discord's `custom_id` has a 100 character limit - if the action ID plus callback token exceed this, posting the card throws a `ValidationError`. Telegram's `callback_data` has a 64 byte limit - buttons that exceed this will throw a `ValidationError`. Keep action IDs short when using `callbackUrl` on these platforms. </Callout> For modals, see [callbackUrl on modals](/docs/modals#callback-urls).