Moving Beyond Markdown: Building Predictable UIs with Slack Block Kit
Stop relying on Markdown for complex Slack messages. Learn how to use Block Kit's JSON schema to build consistent, interactive UIs that work across all Slack clients.
21 Aug 2025, 09:17 UTC

The Problem with Markdown Layouts
For years, developers building Slack integrations relied on a mix of Markdown and legacy "attachments" to structure their messages. While Markdown is excellent for simple text formatting, it fails when you need a precise visual hierarchy, side-by-side elements, or interactive inputs. Relying on whitespace and bolding to create a "UI" leads to inconsistent rendering across the desktop app, mobile devices, and web browsers.
The solution is Block Kit, a JSON-based UI framework. Instead of sending a long string of formatted text, you send an array of structured objects (blocks). This shifts the responsibility of rendering from the developer's string manipulation to Slack's native layout engine, ensuring that a button looks like a button regardless of the client.
The Block Kit Architecture
Block Kit operates on a schema where each "block" represents a specific row or section of the message. This modularity allows you to mix and match different types of content without worrying about breaking the layout.
- Section Blocks: The workhorse of the framework. These handle text, images, and accessory elements (like a single button attached to a piece of text).
- Actions Blocks: Dedicated containers for interactive elements like buttons, date pickers, and overflow menus.
- Input Blocks: Used primarily in modals to collect data via text inputs, checkboxes, or radio buttons.
- Divider Blocks: Simple visual separators to group related information.
Example: Creating an Approval Workflow
Consider a scenario where an engineer needs to approve a deployment. A Markdown message would require a link to an external site. With Block Kit, the approval happens directly inside the chat.
To implement this, you send a POST request to the chat.postMessage API endpoint with the following JSON payload:
{
"channel": "C12345678",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Deployment Request:* v2.4.1-stable\n*Environment:* Production"
}
},
{
"type": "divider"
},
{
"type": "actions",
"elements": [
{
"type": "button",
"text": {
"type": "plain_text",
"text": "Approve"
},
"style": "primary",
"value": "approve_deploy_123",
"action_id": "approve_button"
},
{
"type": "button",
"text": {
"type": "plain_text",
"text": "Reject"
},
"style": "danger",
"value": "reject_deploy_123",
"action_id": "reject_button"
}
]
}
]
}
Handling the Interaction
When a user clicks "Approve," Slack does not magically update the database. It sends an HTTP POST payload to the Request URL you configured in your App Management dashboard. Your server must:
- Acknowledge the request: Return an HTTP 200 OK within 3 seconds, or the user will see an error message.
- Process the action: Use the
action_idandvaluefrom the payload to trigger your backend logic. - Update the UI (Optional): Send a
response_urlrequest to replace the original message with a "Deployment Approved" confirmation.
Engineering Trade-offs and Constraints
While Block Kit provides a professional UI, it introduces specific technical constraints that differ from simple text messages.
| Constraint | Impact | Mitigation |
|---|---|---|
| Block Limit | Maximum of 50 blocks per message. | Use pagination or link to a modal for larger datasets. |
| 3-Second Timeout | Interactions must be acknowledged almost instantly. | Acknowledge the request immediately, then process the logic asynchronously. |
| Public Endpoint | Requires a reachable HTTPS URL for payloads. | Use tools like ngrok for local development or a cloud function for production. |
Verification and Testing
To verify your implementation without deploying code, use the Slack Block Kit Builder. This browser-based tool allows you to paste your JSON and see a live preview of how it renders on different devices. To test the full loop, ensure your app's "Interactivity" toggle is enabled in the Slack App settings; otherwise, buttons will be visible but non-functional.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.