Building Interactive Slack Messages with Block Kit: From Legacy Attachments to Modern Layouts
Stop sending plain text alerts. Learn how to use Slack’s Block Kit to build interactive, structured UI components that let users act directly within a channel.
15 Apr 2026, 09:06 UTC

The Problem with Plain Text Notifications
Most developers start their Slack integrations by sending a simple string of text. While this works for basic alerts, it fails as soon as you need a user to take a specific action—like approving a pull request, updating a ticket status, or selecting a category—without leaving the chat interface. Forcing users to copy‑paste an ID from a Slack message into a separate web dashboard creates friction and slows down workflows.
The solution is Block Kit, Slack's JSON‑based UI framework. Instead of treating a message as a single blob of text, Block Kit allows you to build a vertical stack of structured components. The key takeaway is that Block Kit decouples the definition of the UI from the rendering, allowing you to create interactive, app‑like experiences directly inside a channel.
Understanding the Block Hierarchy
A Block Kit message is essentially an array of blocks. Each block serves a specific layout purpose, and they are rendered in the order they appear in the JSON payload. To build an effective interface, you need to distinguish between content blocks and interactive elements.
- Section Blocks: The workhorse of the framework. These handle text, Markdown, and accessory elements (like a single button or menu) that sit to the right of the text.
- Context Blocks: Used for secondary information. These are smaller, greyed‑out text strings often used for timestamps, user IDs, or status labels.
- Divider Blocks: Simple visual separators that help group related information.
- Input Blocks: Used primarily in modals to collect user data via text inputs or dropdowns.
Mapping Interactions via action_id
When a user clicks a button in a Block Kit message, Slack doesn't just tell you a button was clicked. It sends an HTTP POST payload to your configured Request URL. To handle this at scale, you must use block_id and action_id.
The block_id identifies the specific container, while the action_id identifies the specific trigger. By assigning unique, semantic IDs (e.g., approve_request_btn), your backend can route the request to the correct function without needing to parse the message text or rely on the order of buttons.
Example: A Deployment Approval Component
Imagine a CI/CD bot that notifies a team when a staging deployment is ready for production. Instead of a text message, you can send a structured block payload using the chat.postMessage API.
{\n \"blocks\": [\n {\n \"type\": \"section\",\n \"text\": {\n \"type\": \"mrkdwn\",\n \"text\": \"*Deployment Ready:* Version 2.4.1 is ready for Production.\"\n }\n },\n {\n \"type\": \"section\",\n \"text\": {\n \"type\": \"mrkdwn\",\n \"text\": \"*Changes:* \n- Fixed memory leak in auth module\n- Updated API documentation\"\n }\n },\n {\n \"type\": \"divider\"\n },\n {\n \"type\": \"actions\",\n \"elements\": [\n {\n \"type\": \"button\",\n \"text\": {\n \"type\": \"plain_text\",\n \"text\": \"Approve\"\n },\n \"style\": \"primary\",\n \"action_id\": \"deploy_approve\",\n \"value\": \"build_id_12345\"\n },\n {\n \"type\": \"button\",\n \"text\": {\n \"type\": \"plain_text\",\n \"text\": \"Reject\"\n },\n \"style\": \"danger\",\n \"action_id\": \"deploy_reject\",\n \"value\": \"build_id_12345\"\n }\n ]\n },\n {\n \"type\": \"context\",\n \"elements\": [\n {\n \"type\": \"mrkdwn\",\n \"text\": \"Requested by: @dev_lead | Environment: Production\"\n }\n ]\n }\n ]\n}Implementation Requirements
- Permissions: Your bot must have the
chat:writescope to send these messages. - Endpoint: Provide a publicly accessible HTTPS endpoint in your App Settings under Interactivity & Shortcuts.
- The 3‑Second Rule: Your server must acknowledge the receipt of the interaction payload with an HTTP 200 OK within 3 seconds, or Slack will show the user an error. If your processing takes longer, acknowledge first and then process the task asynchronously.
Limitations and Trade‑offs
While powerful, Block Kit has strict constraints. There is a limit on the number of blocks per message (typically 50), and exceeding this will result in an invalid_payload error. Additionally, visual rendering is responsive; a layout that looks perfectly aligned on the desktop client may wrap text or shift buttons on the mobile app. Always test your layouts on both platforms to ensure critical buttons remain visible.
Verification Workflow
To ensure your UI works before deploying code, follow this verification sequence:
- Prototype: Use the official Block Kit Builder to visually construct the JSON and preview it in your workspace.
- Payload Test: Use a tool like cURL or Postman to send the JSON to
chat.postMessageusing your Bot User OAuth Token. - Interaction Trace: Trigger a button click and inspect the raw JSON payload arriving at your server to verify that the
action_idandvaluefields match your expectations.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.