Blocks and elements
Every block and element type in @slack/types 3.0.0 renders, as do the newer
message-surface blocks Slack has documented but not yet typed (container,
data_table, and data_visualization). Anything outside that inventory still
renders as a visible, labeled fallback (see
Unknown blocks and fallbacks).
Blocks
| Block type | Notes |
|---|---|
section | Text, up to 10 fields, and any accessory; unknown accessories fall back visibly |
rich_text | Full container and inline inventory; see below |
header | Semantic h1–h4 via the level field; out-of-range levels clamp |
context | Text and image elements |
divider | — |
image | URL images render; slack_file IDs render an alt-labeled placeholder (a file ID has no fetchable URL) |
actions | All interactive elements below |
input | Labels, hints, and all input elements below |
markdown | Minimal Markdown subset: headings, paragraphs, quotes, lists (including task lists), fenced code, tables, dividers, inline emphasis |
table | raw_text, raw_number, and rich_text cells; column alignment and wrapping; first row renders with column-header semantics |
data_table | Caption, header/row semantics, pagination; renders safely with empty rows |
data_visualization | pie, bar, line, and area charts with legends; a zero-total pie renders a labeled no-data state |
container | Legal Slack child blocks, collapsible state, header/subtitle/icon |
card | Title, subtitle, body, hero image, icon, actions |
carousel | Card elements |
alert | Info/warning/error/success levels (modal surface in Slack) |
context_actions | — |
file | — |
plan | Title and task cards |
task_card | — |
video | — |
The newer message blocks
Slack's recent additions are the ones most likely to decide whether this renderer covers
what you need, and they are hard to picture from a table row. card and carousel:
View payload JSON
{
"blocks": [
{
"type": "card",
"slack_icon": {
"type": "icon",
"name": "rocket"
},
"title": {
"type": "plain_text",
"text": "Release 2.41.0"
},
"subtitle": {
"type": "plain_text",
"text": "Shipped to production"
},
"body": {
"type": "mrkdwn",
"text": "32 checks passed. Rollout took *4m 12s*."
},
"subtext": {
"type": "plain_text",
"text": "Triggered from main"
},
"actions": [
{
"type": "button",
"action_id": "open_run",
"text": {
"type": "plain_text",
"text": "Open run"
}
}
]
},
{
"type": "carousel",
"elements": [
{
"type": "card",
"title": {
"type": "plain_text",
"text": "us-east-1"
},
"body": {
"type": "plain_text",
"text": "412 errors, p95 188 ms"
}
},
{
"type": "card",
"title": {
"type": "plain_text",
"text": "eu-west-1"
},
"body": {
"type": "plain_text",
"text": "17 errors, p95 176 ms"
}
}
]
}
]
}A collapsible container, a paginated data_table, and a bar chart:
DeploymentProduction
| Region | Errors |
|---|---|
| us-east-1 | 412 |
| eu-west-1 | 17 |
| ap-south-1 | 233 |
| eu-central-1 | 88 |
| us-west-2 | 51 |
Weekly output
View payload JSON
{
"blocks": [
{
"type": "container",
"title": {
"type": "plain_text",
"text": "Deployment"
},
"subtitle": {
"type": "plain_text",
"text": "Production"
},
"is_collapsible": true,
"has_header_divider": true,
"child_blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Version:* 2.41.0"
}
},
{
"type": "divider"
},
{
"type": "actions",
"elements": [
{
"type": "button",
"action_id": "view_logs",
"text": {
"type": "plain_text",
"text": "View logs"
}
}
]
}
]
},
{
"type": "data_table",
"caption": "Error budget by region",
"page_size": 5,
"row_header_column_index": 0,
"rows": [
[
{
"type": "raw_text",
"text": "Region"
},
{
"type": "raw_text",
"text": "Errors"
}
],
[
{
"type": "raw_text",
"text": "us-east-1"
},
{
"type": "raw_number",
"value": 412,
"text": "412"
}
],
[
{
"type": "raw_text",
"text": "eu-west-1"
},
{
"type": "raw_number",
"value": 17,
"text": "17"
}
],
[
{
"type": "raw_text",
"text": "ap-south-1"
},
{
"type": "raw_number",
"value": 233,
"text": "233"
}
],
[
{
"type": "raw_text",
"text": "eu-central-1"
},
{
"type": "raw_number",
"value": 88,
"text": "88"
}
],
[
{
"type": "raw_text",
"text": "us-west-2"
},
{
"type": "raw_number",
"value": 51,
"text": "51"
}
],
[
{
"type": "raw_text",
"text": "sa-east-1"
},
{
"type": "raw_number",
"value": 9,
"text": "9"
}
]
]
},
{
"type": "data_visualization",
"title": "Weekly output",
"chart": {
"type": "bar",
"axis_config": {
"categories": [
"Mon",
"Tue",
"Wed"
],
"y_label": "Tasks"
},
"series": [
{
"name": "Completed",
"data": [
{
"label": "Mon",
"value": 8
},
{
"label": "Tue",
"value": 12
},
{
"label": "Wed",
"value": 10
}
]
}
]
}
}
]
}alert is a modal block, so it renders here on the modal surface:
View payload JSON
{
"blocks": [
{
"type": "alert",
"level": "info",
"text": {
"type": "plain_text",
"text": "Canary is live."
}
},
{
"type": "alert",
"level": "warning",
"text": {
"type": "plain_text",
"text": "Retries elevated in us-east-1."
}
},
{
"type": "alert",
"level": "error",
"text": {
"type": "plain_text",
"text": "Rollout halted at 40%."
}
},
{
"type": "alert",
"level": "success",
"text": {
"type": "plain_text",
"text": "All regions healthy."
}
}
]
}Rich text
Containers: rich_text_section, rich_text_list (real ul/ol with
ordered offset, per-depth markers, indent bounded to 0–8),
rich_text_quote (payload border honored), and rich_text_preformatted
(language and border honored).
Inline elements: text with deterministically nested bold / italic /
strike / code styling, link (protocol-checked), emoji, user,
channel, usergroup, team, broadcast, date, color (swatch and
value), and compact textual fallbacks for citation and Slack's internal
reference mentions (canvas, file, workflow, and similar). Unknown inline
types render a visible fallback.
Interactive elements
| Group | Types |
|---|---|
| Buttons | button (default, primary, danger; URL buttons render as links) |
| Selects | static_select, external_select, users_select, channels_select, conversations_select, and their multi_* variants |
| Menus | overflow (Slack's ellipsis button; the menu does not open and options are not displayed) |
| Choices | checkboxes, radio_buttons |
| Inputs | plain_text_input, email_text_input, url_text_input, number_input, datepicker, timepicker, datetimepicker, file_input, rich_text_input |
| Workflow | workflow_button (renders as a button; does not emit onAction) |
| Context actions | icon_button, feedback_buttons (inside context_actions) |
| Images | image (element and accessory) |
Apart from workflow_button and image, all of these report through
onAction when they carry an action_id. See
Handling actions.
Mrkdwn formatting
Mrkdwn text (section text, fields, context elements) supports:
| Syntax | Rendering |
|---|---|
*bold*, _italic_, ~strike~ | Semantic strong/em/s, nesting allowed |
`code` and ``` fenced blocks | Inline code and preformatted blocks |
<https://…|label> | Protocol-checked links; bare http(s)/mailto URLs auto-link |
<@U…>, <#C…>, <!subteam^S…> | Mentions, with resolver and payload-label fallbacks |
<!here>, <!channel>, <!everyone> | Broadcast mentions |
<!date^ts^{token}|fallback> | Deterministic UTC date formatting; fallback for relative tokens |
:shortcode: | Emoji: 36 built-in glyphs, literal :name: for every other shortcode |
& < > | Decoded everywhere, including links, labels, and code |
Emoji shortcodes require token boundaries, so times and ratios like
12:30:45 stay literal text.
The exact TypeScript shape of every block and element is on Exported types.