MM Blocks¶
Technical complexity: Low-code
MM Blocks are Mattermost’s structured format for rich, interactive posts. Use them to build notifications with text, images, layouts, buttons, and menus directly in a post’s props—without relying on Slack-compatible message attachments.
MM Blocks replace message attachments as the recommended way to create interactive messages. Existing attachment-based payloads continue to work: clients translate them into MM Blocks at render time.
Overview¶
Interactive posts combine:
Content blocks in
props.mm_blocks— text, images, dividers, containers, columns, collapsible sections, buttons, and static selects.Action definitions in
props.mm_blocks_actions— map eachaction_idto an integration URL or in-app navigation target.
When a post is created, the server encrypts props.mm_blocks_actions into a single cookie string before the post is sent to clients. Users interact with buttons and menus in the channel; Mattermost calls your integration and can update the post or return an ephemeral reply.
MM Blocks are supported on web, desktop, and mobile clients. Availability is controlled by the MM_FEATUREFLAGS_MMBLOCKSENABLED feature flag (defaults to true). Set MM_FEATUREFLAGS_MMBLOCKSENABLED=false on self-hosted deployments to disable rendering and action dispatch for MM Blocks payloads.
Quick start¶
This incoming webhook payload renders a short message with a primary button. The button calls an external integration URL when clicked.
{
"text": "Deployment finished",
"props": {
"mm_blocks": [
{
"type": "text",
"text": "Build **#42** deployed to *staging*."
},
{
"type": "divider"
},
{
"type": "button",
"text": "View logs",
"style": "primary",
"action_id": "view_logs"
}
],
"mm_blocks_actions": {
"view_logs": {
"type": "external",
"url": "https://example.com/integrations/view-logs",
"context": {
"deployment_id": "42"
}
}
}
}
}
Post properties¶
Property |
Description |
|---|---|
|
Array of block objects that define layout and interactive controls. See Block types below. |
|
Object keyed by |
You can include props.mm_blocks and props.mm_blocks_actions in any payload that supports a props object, including incoming webhooks, outgoing webhooks responses, slash command responses, bot posts, and ephemeral posts created through the API.
Block types¶
Type |
Description |
|---|---|
|
Markdown text. Optional |
|
Horizontal rule between blocks. |
|
Image with |
|
Labeled button. Requires |
|
Dropdown menu. Requires |
|
Groups nested blocks in |
|
Multi-column layout. A |
|
Expandable section with |
Malformed block entries are skipped at render time; valid blocks in the same array still display.
Container example¶
{
"props": {
"mm_blocks": [
{
"type": "container",
"accent_color": "#439FE0",
"border": true,
"gap": "small",
"content": [
{"type": "text", "text": "**Incident summary**"},
{"type": "text", "text": "Severity: high", "is_subtle": true, "size": "small"},
{
"type": "column_set",
"columns": [
{
"type": "column",
"width": "stretch",
"items": [{"type": "text", "text": "Service: **payments**"}]
},
{
"type": "column",
"width": "stretch",
"items": [{"type": "text", "text": "Region: **us-east-1**"}]
}
]
}
]
}
]
}
}
Interactive actions¶
Define one entry in props.mm_blocks_actions for each action_id used by a button or static_select block.
Action type |
Behavior |
|---|---|
|
Mattermost sends an HTTP POST to |
|
Navigates the user to |
Optional query on an action definition is merged into the target URL. Per-control query on a block is sent in the post-action request body and merged after the action-level query.
When a user selects a menu option, Mattermost includes selected_option in the post-action request with the chosen value.
Action API¶
When a user activates a control, the client calls:
POST /api/v4/posts/{post_id}/actions/{action_id}
The request body may include:
Field |
Description |
|---|---|
|
Encrypted action cookie for the post (supplied automatically by Mattermost clients). |
|
Value from a |
|
Per-control query parameters from the block definition. |
|
Source format for the action: |
A successful response returns status, trigger_id, and optionally goto_location for openURL actions.
action_id values may contain letters, numbers, underscores (_), and hyphens (-).
Legacy formats¶
Mattermost clients still accept older interactive payload shapes and translate them into MM Blocks for rendering. When multiple formats are present, clients use this priority:
props.mm_blocks(native)props.blocks(Slack Block Kit)props.cards(Adaptive Cards)attachmentsin webhook and slash command payloads (stored asprops.attachmentson the post; Slack-compatible message attachments)
Note
Message attachments remain supported for backward compatibility. New integrations should use props.mm_blocks and props.mm_blocks_actions instead of nesting interactive controls under top-level attachments.
Attachment actions map to MM Blocks as follows:
Attachment
actions[].idbecomesaction_idon buttons and selects.Attachment
actions[].integration.urlis used for external dispatch (equivalent toprops.mm_blocks_actionsentries).Button
stylevalues (primary,good,danger, hex colors, and so on) are preserved.
Migrating from attachments¶
Move visual content (text, fields, images) into typed MM Blocks—use
containerblocks withaccent_colorinstead of attachmentcolor, andtextblocks instead ofpretext/text/ field values.Replace
actionsarrays withbuttonandstatic_selectblocks that referenceaction_idvalues.Add a
props.mm_blocks_actionsmap keyed by those IDs withtype,url, andcontext(previouslyintegration.urlandintegration.context).Optionally add
textabove the blocks for notifications and search when the block content alone is not enough context.
Example migration — attachment button:
{
"attachments": [
{
"text": "Approve this change?",
"actions": [
{
"type": "button",
"id": "approve",
"name": "Approve",
"style": "primary",
"integration": {
"url": "https://example.com/actions/approve",
"context": {"id": "cr-1"}
}
}
]
}
]
}
Equivalent MM Blocks payload:
{
"text": "Approve this change?",
"props": {
"mm_blocks": [
{"type": "text", "text": "Approve this change?"},
{
"type": "button",
"text": "Approve",
"style": "primary",
"action_id": "approve"
}
],
"mm_blocks_actions": {
"approve": {
"type": "external",
"url": "https://example.com/actions/approve",
"context": {"id": "cr-1"}
}
}
}
}
End-user experience¶
See Extend Mattermost with integrations for end-user guidance on buttons, menus, collapsible sections, and expandable content. See Troubleshoot MM Blocks if content does not render or respond as expected.
On all supported clients, users can tap buttons, open static select menus, and expand or collapse collapsible sections inline in the channel.
Containers with a max_height preset clip overflowing content. On mobile, users select the expand control on a clipped region to open a full-screen Scrollable content view. On web and desktop, the same regions scroll inside the post.
Legacy attachment posts render with the same MM Blocks UI after client-side translation, so button and menu behavior is consistent across formats.