Skip to main content

Card actions

A card combines text with up to three buttons. These examples build two cards with the same approval and rejection actions; the second adds a Details button.

Slackblocks preserves the order supplied to actions in the serialized payload. Slack controls the visual arrangement, so array order is not a positioning API:

CardVisual arrangement
Two buttonsReject and Approve form a group on the right, with Reject first.
Three buttonsReject sits at the far left; Details and Approve form a group on the right.

Primary buttons appear furthest right. Adding the third button moves the danger button across the card. This card-specific rule does not change an ordinary Actions block.

The official card reference contains this clarification, first observed on 6 November 2026. The two- and three-button arrangements were also verified in the Slack stress workspace on 7 November 2026, including all six input orders for one primary, one danger, and one default button. This is a documentation clarification, with no new field or caller migration.

Output

Local preview of the selected language’s tested example. Slack client appearance may differ; controls here do not send requests.

Two buttons
Review release-42.
Three buttons
Review release-42.
Serialized output
{
"channel": "C1",
"mrkdwn": true,
"blocks": [
{
"type": "card",
"block_id": "card_two",
"title": {
"type": "mrkdwn",
"text": "Two buttons"
},
"body": {
"type": "mrkdwn",
"text": "Review release-42."
},
"actions": [
{
"type": "button",
"text": {
"type": "plain_text",
"text": "Approve"
},
"action_id": "approve",
"style": "primary",
"value": "release-42"
},
{
"type": "button",
"text": {
"type": "plain_text",
"text": "Reject"
},
"action_id": "reject",
"style": "danger",
"value": "release-42"
}
]
},
{
"type": "card",
"block_id": "card_three",
"title": {
"type": "mrkdwn",
"text": "Three buttons"
},
"body": {
"type": "mrkdwn",
"text": "Review release-42."
},
"actions": [
{
"type": "button",
"text": {
"type": "plain_text",
"text": "Approve"
},
"action_id": "approve",
"style": "primary",
"value": "release-42"
},
{
"type": "button",
"text": {
"type": "plain_text",
"text": "Reject"
},
"action_id": "reject",
"style": "danger",
"value": "release-42"
},
{
"type": "button",
"text": {
"type": "plain_text",
"text": "Details"
},
"action_id": "details",
"value": "release-42"
}
]
}
],
"text": "Card actions"
}

Build the cards​

The code deliberately supplies Approve before Reject. Expand Serialized output above to compare that array with the preview's visual arrangement. Each button retains its action ID and request value. Your application still needs to handle and acknowledge interactions; constructing these messages does not send them.

from slackblocks import Button, CardBlock, Message

approve = Button("Approve", action_id="approve", value="release-42", style="primary")
reject = Button("Reject", action_id="reject", value="release-42", style="danger")
details = Button("Details", action_id="details", value="release-42")
message = Message(channel="C1", text="Card actions", blocks=[
CardBlock(title="Two buttons", body="Review release-42.",
actions=[approve, reject], block_id="card_two"),
CardBlock(title="Three buttons", body="Review release-42.",
actions=[approve, reject, details], block_id="card_three"),
])
print(message.json())