---
title: Actions
description: Handle button clicks and interactive card events across platforms.
type: guide
prerequisites:
  - /docs/cards
related:
  - /docs/modals
---

# Actions



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. Other platforms will receive a no-op or fallback behavior.
</Callout>
