Handling actions

Buttons, selects, overflow menus, checkboxes, radio buttons, inputs, and the context_actions elements all report user interaction through a single onAction callback:

import { BlockKit, type BlockKitAction, type BlockKitInput } from "react-blockkit";

export function Preview({ data }: { data: BlockKitInput }) {
  return (
    <BlockKit
      data={data}
      onAction={(action: BlockKitAction) => {
        console.log(action.actionId, action.value);
      }}
    />
  );
}

BlockKitAction is react-blockkit's own local event shape, not the interactivity payload Slack POSTs to an app. Nothing is sent to Slack. onAction hands you the interaction and your app decides what to do with it, whether that is updating local state or calling your own backend.

The BlockKitAction shape

FieldTypeMeaning
actionIdstringThe element's action_id
typestringThe element's type ("button", "static_select", …)
blockIdstring | undefinedThe enclosing block's block_id, when set
valuestring | undefinedSingle value (button value, selected option, input text)
valuesreadonly string[] | undefinedMultiple values (multi-selects, checked checkboxes)

Elements without an action_id never emit, so the callback fires only when there is an ID to report.

What each element emits

ElementFires onPayload
ButtonClickvalue when the button declares one; URL buttons render as links and still emit
Overflow menuClickactionId and type only; the ellipsis button opens no menu, so no option is reported
Select (all variants)Selection changevalue, or values for multi_* variants
CheckboxesTogglevalues: every currently checked option
Radio buttonsSelectionvalue of the chosen option
Text/email/URL/number inputsEach changevalue: the current text
Rich text inputEach changevalue: the editor's plain text
File inputSelectionvalue: the first selected file's name
Date pickerClickvalue: the initial_date, or an empty string (renders as a button)
Time and datetime pickersEach changevalue: the control's current value
Icon buttonClickvalue when the element declares one
Feedback buttonsClickvalue from the pressed button's positive_button.value or negative_button.value

Try it

Interact with the message below; the local BlockKitAction each element emits appears under the render.

PR #482 is ready for review.
Interact with the message above. The BlockKitAction appears here.
View payload JSON
{
  "blocks": [
    {
      "type": "section",
      "block_id": "review",
      "text": {
        "type": "mrkdwn",
        "text": "*PR #482* is ready for review."
      },
      "accessory": {
        "type": "static_select",
        "action_id": "assign_reviewer",
        "placeholder": {
          "type": "plain_text",
          "text": "Assign reviewer"
        },
        "options": [
          {
            "text": {
              "type": "plain_text",
              "text": "Maya"
            },
            "value": "maya"
          },
          {
            "text": {
              "type": "plain_text",
              "text": "Sam"
            },
            "value": "sam"
          }
        ]
      }
    },
    {
      "type": "actions",
      "block_id": "decision",
      "elements": [
        {
          "type": "button",
          "action_id": "approve",
          "text": {
            "type": "plain_text",
            "text": "Approve"
          },
          "style": "primary",
          "value": "pr-482"
        },
        {
          "type": "button",
          "action_id": "request_changes",
          "text": {
            "type": "plain_text",
            "text": "Request changes"
          }
        }
      ]
    }
  ]
}

Composed blocks

When rendering blocks individually, put onAction on BlockKitProvider, the same context <BlockKit /> uses internally:

import {
  ActionsBlock,
  BlockKitProvider,
  type ActionsBlockData,
  type BlockKitAction,
} from "react-blockkit";

export function record(action: BlockKitAction) {
  console.log(action);
}

export function Preview({ actionsBlock }: { actionsBlock: ActionsBlockData }) {
  return (
    <BlockKitProvider onAction={record}>
      <ActionsBlock block={actionsBlock} />
    </BlockKitProvider>
  );
}