Using Blocks
Blocks are the fundamental visual units of a Slack message. Each block type renders as a different UI component (a section of text, a header, a divider, an image, a row of buttons, and so on). A Message is composed of one or more blocks, rendered top-to-bottom.
This page walks through every block type supported by slackblocks, with:
- A short description of what the block is for.
- The
slackblockscode to construct it in your selected language. - The JSON payload that's produced.
- A screenshot of how it looks in Slack.
For the reverse mapping — looking up a class by name — see the Blocks reference. For interactive UI bits (buttons, menus, date pickers) that go inside blocks, see Elements.
For exact setters and return types, see the TypeScript API reference. Interactive controls such as buttons, menus, and date pickers are documented alongside the other element builders.
For fluent constructors, JSON types, and validation errors, see the Go API reference. Interactive controls such as buttons, menus, and date pickers are grouped under Elements.
For concrete fluent builders, immutable values, and validation errors, see the Java API reference. Interactive controls such as buttons, menus, and date pickers are grouped under Elements.
For constructors, typed properties, and validation errors, see the C# API reference. Interactive controls such as buttons, menus, and date pickers are grouped under Elements.
For keyword constructors, immutable values, and validation errors, see the Ruby API reference. Interactive controls are in Elements. The Ruby snippets below produce the same payloads shown in the JSON tabs.
Section Block
A section is the most versatile block. It shows text, a two-column grid of fields, or both, and can carry one interactive accessory such as a button, menu, or image.
Provide text, fields, or both. text allows up to 3,000 characters, and fields allows up to 10 items of up to 2,000 characters each.
- slackblocks
- JSON
- Slack UI
from slackblocks import CheckboxGroup, Option, SectionBlock
SectionBlock(
text="This is a section block with a checkbox accessory.",
block_id="fake_block_id",
accessory=CheckboxGroup(
action_id="checkboxes-action",
options=[
Option(
text="*Your Only Option*",
value="option_one"
)
]
)
)
import { Checkboxes, Markdown, Option, SectionBlock } from "@nicklambourne/slackblocks";
SectionBlock()
.text("This is a section block with a checkbox accessory.")
.blockId("fake_block_id")
.accessory(
Checkboxes()
.actionId("checkboxes-action")
.options(Option().text(Markdown().text("*Your Only Option*")).value("option_one")),
)
.build();
block, err := slackblocks.NewSectionBlock().
Text("This is a section block with a checkbox accessory.").
BlockID("fake_block_id").
Accessory(
slackblocks.NewCheckboxes().
ActionID("checkboxes-action").
Options(
slackblocks.NewOption().
TextObject(slackblocks.NewMarkdown().Text("*Your Only Option*")).
Value("option_one"),
),
).
Build()
SectionBlock block = SectionBlock.builder()
.markdownText("This is a section block with a checkbox accessory.")
.blockId("fake_block_id")
.accessory(CheckboxesElement.builder()
.actionId("checkboxes-action")
.options(Option.builder()
.text(MarkdownText.of("*Your Only Option*"))
.value("option_one")
.build())
.build())
.build();
var block = new SectionBlock(
text: "This is a section block with a checkbox accessory.",
accessory: new CheckboxesElement(
"checkboxes-action",
options: [new Option(new MarkdownText("*Your Only Option*"), "option_one")]),
blockId: "fake_block_id");
require "slackblocks"
include Slackblocks
block = SectionBlock.new(
text: MarkdownText.new(text: "This is a section block with a checkbox accessory."),
accessory: CheckboxesElement.new(
action_id: "checkboxes-action",
options: [Option.new(text: MarkdownText.new(text: "*Your Only Option*"), value: "option_one")]
),
block_id: "fake_block_id"
)
puts block.to_json
{
"type": "section",
"block_id": "fake_block_id",
"text": {
"type": "mrkdwn",
"text": "This is a section block with a checkbox accessory."
},
"accessory": {
"type": "checkboxes",
"options": [
{
"text": {
"type": "mrkdwn",
"text": "*Your Only Option*"
},
"value": "option_one"
}
],
"action_id": "checkboxes-action"
}
}

Rich Text Block
Rich text carries formatted content built from sections, lists, preformatted code, and quotes. Inline elements add bold, italic, strikethrough, and code styling, along with links, emoji, and user, channel, or user group mentions.
Required: elements.
- slackblocks
- JSON
- Slack UI
from slackblocks import RichTextBlock, RichTextSection, RichText
RichTextBlock(
RichTextSection(
[
RichText(
"You 'bout to witness hip-hop in its most purest\n",
bold=True,
),
RichText(
"Most rawest form, flow almost flawless\n",
strike=True,
),
RichText(
"Most hardest, most honest known artist\n",
italic=True,
),
]
),
block_id="fake_block_id",
)
import { RichText, RichTextBlock, RichTextSection } from "@nicklambourne/slackblocks";
RichTextBlock()
.blockId("fake_block_id")
.elements(
RichTextSection().elements(
RichText().text("You 'bout to witness hip-hop in its most purest\n").style({ bold: true }),
RichText().text("Most rawest form, flow almost flawless\n").style({ strike: true }),
RichText().text("Most hardest, most honest known artist\n").style({ italic: true }),
),
)
.build();
block, err := slackblocks.NewRichTextBlock().
BlockID("fake_block_id").
Elements(
slackblocks.NewRichTextSection().Elements(
slackblocks.NewRichText().Text("You 'bout to witness hip-hop in its most purest\n").Style(slackblocks.RichTextStyle{"bold": true}),
slackblocks.NewRichText().Text("Most rawest form, flow almost flawless\n").Style(slackblocks.RichTextStyle{"strike": true}),
slackblocks.NewRichText().Text("Most hardest, most honest known artist\n").Style(slackblocks.RichTextStyle{"italic": true}),
),
).
Build()
RichTextBlock block = RichTextBlock.builder()
.blockId("fake_block_id")
.elements(RichTextSection.builder()
.elements(
RichTextText.builder().text("You 'bout to witness hip-hop in its most purest\n")
.bold(true).build(),
RichTextText.builder().text("Most rawest form, flow almost flawless\n")
.strike(true).build(),
RichTextText.builder().text("Most hardest, most honest known artist\n")
.italic(true).build())
.build())
.build();
var block = new RichTextBlock(
elements: [
new RichTextSection(
elements: [
new RichTextText(
"You 'bout to witness hip-hop in its most purest\n",
style: new RichTextStyle(bold: true)),
new RichTextText(
"Most rawest form, flow almost flawless\n",
style: new RichTextStyle(strike: true)),
new RichTextText(
"Most hardest, most honest known artist\n",
style: new RichTextStyle(italic: true)),
]),
],
blockId: "fake_block_id");
require "slackblocks"
include Slackblocks
block = RichTextBlock.new(
elements: [
RichTextSection.new(
elements: [
RichTextText.new(
text: "You 'bout to witness hip-hop in its most purest\n",
style: RichTextStyle.new(bold: true)
),
RichTextText.new(
text: "Most rawest form, flow almost flawless\n",
style: RichTextStyle.new(strike: true)
),
RichTextText.new(
text: "Most hardest, most honest known artist\n",
style: RichTextStyle.new(italic: true)
)
]
)
],
block_id: "fake_block_id"
)
puts block.to_json
{
"type": "rich_text",
"block_id": "fake_block_id",
"elements": [
{
"type": "rich_text_section",
"elements": [
{
"type": "text",
"text": "You 'bout to witness hip-hop in its most purest\n",
"style": {
"bold": true
}
},
{
"type": "text",
"text": "Most rawest form, flow almost flawless\n",
"style": {
"strike": true
}
},
{
"type": "text",
"text": "Most hardest, most honest known artist\n",
"style": {
"italic": true
}
}
]
}
]
}

Header Block
A header shows large, bold plain text that introduces a group of blocks. Plain strings are converted to Slack plain_text objects automatically.
Required: text (up to 150 characters).
- slackblocks
- JSON
- Slack UI
from slackblocks import HeaderBlock
HeaderBlock(
"This is a header block",
block_id="fake_block_id",
)
import { HeaderBlock } from "@nicklambourne/slackblocks";
HeaderBlock().text("This is a header block").blockId("fake_block_id").build();
block, err := slackblocks.NewHeaderBlock().
Text("This is a header block").
BlockID("fake_block_id").
Build()
HeaderBlock block = HeaderBlock.builder()
.text("This is a header block")
.blockId("fake_block_id")
.build();
var block = new HeaderBlock("This is a header block", blockId: "fake_block_id");
require "slackblocks"
include Slackblocks
block = HeaderBlock.new(text: PlainText.new(text: "This is a header block"), block_id: "fake_block_id")
puts block.to_json
{
"type": "header",
"block_id": "fake_block_id",
"text": {
"type": "plain_text",
"text": "This is a header block"
}
}

Markdown Block
Slack added the markdown block type in 2024, primarily for AI / agentic apps. Unlike the mrkdwn text inside a Section Block, MarkdownBlock renders GitHub-flavored Markdown, supporting tables, code blocks, and richer list semantics.
text is required (1 - 12,000 characters).
- slackblocks
- JSON
- Slack UI
from slackblocks import MarkdownBlock
MarkdownBlock(
text="**Hello!** Markdown blocks support _GitHub-flavored_ syntax.",
block_id="fake_block_id",
)
import { MarkdownBlock } from "@nicklambourne/slackblocks";
MarkdownBlock()
.text("**Hello!** Markdown blocks support _GitHub-flavored_ syntax.")
.blockId("fake_block_id")
.build();
block, err := slackblocks.NewMarkdownBlock().
Text("**Hello!** Markdown blocks support _GitHub-flavored_ syntax.").
BlockID("fake_block_id").
Build()
MarkdownBlock block = MarkdownBlock.builder()
.text("**Hello!** Markdown blocks support _GitHub-flavored_ syntax.")
.blockId("fake_block_id")
.build();
var block = new MarkdownBlock(
"**Hello!** Markdown blocks support _GitHub-flavored_ syntax.",
blockId: "fake_block_id");
require "slackblocks"
include Slackblocks
block = MarkdownBlock.new(
text: "**Hello!** Markdown blocks support _GitHub-flavored_ syntax.",
block_id: "fake_block_id"
)
puts block.to_json
{
"type": "markdown",
"block_id": "fake_block_id",
"text": "**Hello!** Markdown blocks support _GitHub-flavored_ syntax."
}
See the Slack reference for the supported Markdown features.
Image Block
An image block displays a standalone image from a URL, with alternative text for screen readers and an optional plain-text title.
Required: image_url (up to 3,000 characters) and alt_text (up to 2,000 characters).
- slackblocks
- JSON
- Slack UI
from slackblocks import ImageBlock
ImageBlock(
image_url="https://api.slack.com/img/blocks/bkb_template_images/beagle.png",
alt_text="a beagle",
title="dog",
block_id="fake_block_id",
)
import { ImageBlock } from "@nicklambourne/slackblocks";
ImageBlock()
.imageUrl("https://api.slack.com/img/blocks/bkb_template_images/beagle.png")
.altText("a beagle")
.title("dog")
.blockId("fake_block_id")
.build();
block, err := slackblocks.NewImageBlock().
ImageURL("https://api.slack.com/img/blocks/bkb_template_images/beagle.png").
AltText("a beagle").
Title("dog").
BlockID("fake_block_id").
Build()
ImageBlock block = ImageBlock.builder()
.imageUrl("https://api.slack.com/img/blocks/bkb_template_images/beagle.png")
.altText("a beagle")
.title("dog")
.blockId("fake_block_id")
.build();
var block = new ImageBlock(
"https://api.slack.com/img/blocks/bkb_template_images/beagle.png",
"a beagle",
title: "dog",
blockId: "fake_block_id");
require "slackblocks"
include Slackblocks
block = ImageBlock.new(
image_url: "https://api.slack.com/img/blocks/bkb_template_images/beagle.png",
alt_text: "a beagle",
title: PlainText.new(text: "dog"),
block_id: "fake_block_id"
)
puts block.to_json
{
"type": "image",
"block_id": "fake_block_id",
"image_url": "https://api.slack.com/img/blocks/bkb_template_images/beagle.png",
"alt_text": "a beagle",
"title": {
"type": "plain_text",
"text": "dog"
}
}

Input Block
An input block pairs a label with one input element, such as a text input, select menu, or date picker, to collect a value from the user. Input blocks are most common in modals, and can also appear in messages and App Home.
Required: label (up to 2,000 characters) and element. Set optional to allow submission without a value, and dispatch_action to receive an interaction payload as the value changes.
- slackblocks
- JSON
- Slack UI
from slackblocks import InputBlock, Text, TextType, PlainTextInput
InputBlock(
label=Text("Label", type_=TextType.PLAINTEXT, emoji=True),
hint=Text("Hint", type_=TextType.PLAINTEXT, emoji=True),
element=PlainTextInput(action_id="action"),
block_id="fake_block_id",
optional=True,
)
import { InputBlock, PlainText, PlainTextInput } from "@nicklambourne/slackblocks";
InputBlock()
.label(PlainText().text("Label").emoji(true))
.hint(PlainText().text("Hint").emoji(true))
.element(PlainTextInput().actionId("action"))
.blockId("fake_block_id")
.optional(true)
.build();
block, err := slackblocks.NewInputBlock().
LabelObject(slackblocks.NewPlainText().Text("Label").Emoji(true)).
HintObject(slackblocks.NewPlainText().Text("Hint").Emoji(true)).
Element(slackblocks.NewPlainTextInput().ActionID("action")).
BlockID("fake_block_id").
Optional(true).
Build()
InputBlock block = InputBlock.builder()
.label(PlainText.builder().text("Label").emoji(true).build())
.hint(PlainText.builder().text("Hint").emoji(true).build())
.element(PlainTextInputElement.builder().actionId("action").build())
.blockId("fake_block_id")
.optional(true)
.build();
var block = new InputBlock(
new PlainText("Label", emoji: true),
element: new PlainTextInputElement("action"),
hint: new PlainText("Hint", emoji: true),
optional: true,
blockId: "fake_block_id");
require "slackblocks"
include Slackblocks
block = InputBlock.new(
label: PlainText.new(text: "Label", emoji: true),
element: PlainTextInputElement.new(action_id: "action"),
block_id: "fake_block_id",
hint: PlainText.new(text: "Hint", emoji: true),
optional: true
)
puts block.to_json
{
"type": "input",
"block_id": "fake_block_id",
"label": {
"type": "plain_text",
"text": "Label",
"emoji": true
},
"element": {
"type": "plain_text_input",
"action_id": "action"
},
"hint": {
"type": "plain_text",
"text": "Hint",
"emoji": true
},
"optional": true
}

Divider Block
A divider draws a horizontal rule between blocks, much like an HTML <hr> element.
No fields are required.
- slackblocks
- JSON
- Slack UI
from slackblocks import DividerBlock
DividerBlock(block_id="fake_block_id")
import { DividerBlock } from "@nicklambourne/slackblocks";
DividerBlock().blockId("fake_block_id").build();
block, err := slackblocks.NewDividerBlock().BlockID("fake_block_id").Build()
DividerBlock block = DividerBlock.builder().blockId("fake_block_id").build();
var block = new DividerBlock(blockId: "fake_block_id");
require "slackblocks"
include Slackblocks
block = DividerBlock.new(block_id: "fake_block_id")
puts block.to_json
{
"type": "divider",
"block_id": "fake_block_id"
}

File Block
A file block displays a remote file that was previously added to Slack with the files.remote.add API. It references the existing file by ID and does not upload anything itself.
Required: external_id. source defaults to remote, the only value Slack currently accepts.
- slackblocks
- JSON
- Slack UI
from slackblocks import FileBlock
FileBlock(
external_id="external_id",
block_id="fake_block_id",
)
import { FileBlock } from "@nicklambourne/slackblocks";
FileBlock().externalId("external_id").blockId("fake_block_id").build();
block, err := slackblocks.NewFileBlock().
ExternalID("external_id").
BlockID("fake_block_id").
Build()
FileBlock block = FileBlock.builder()
.externalId("external_id")
.blockId("fake_block_id")
.build();
var block = new FileBlock("external_id", blockId: "fake_block_id");
require "slackblocks"
include Slackblocks
block = FileBlock.new(external_id: "external_id", source: "remote", block_id: "fake_block_id")
puts block.to_json
{
"type": "file",
"external_id": "external_id",
"source": "remote",
"block_id": "fake_block_id"
}

- Note that this example comes from the Slack Web API docs.
Context Block
A context block shows small, secondary images and text, such as an author, a timestamp, or a status line beneath other content.
Required: elements (up to 10 images or text objects).
- slackblocks
- JSON
- Slack UI
from slackblocks import ContextBlock, Text
ContextBlock(
elements=[
Text("Hello, world!"),
],
block_id="fake_block_id"
)
import { ContextBlock, Markdown } from "@nicklambourne/slackblocks";
ContextBlock()
.elements(Markdown().text("Hello, world!"))
.blockId("fake_block_id")
.build();
block, err := slackblocks.NewContextBlock().
Elements(slackblocks.NewMarkdown().Text("Hello, world!")).
BlockID("fake_block_id").
Build()
ContextBlock block = ContextBlock.builder()
.elements(MarkdownText.of("Hello, world!"))
.blockId("fake_block_id")
.build();
var block = new ContextBlock(elements: [new MarkdownText("Hello, world!")], blockId: "fake_block_id");
require "slackblocks"
include Slackblocks
block = ContextBlock.new(elements: [MarkdownText.new(text: "Hello, world!")], block_id: "fake_block_id")
puts block.to_json
{
"type": "context",
"block_id": "fake_block_id",
"elements": [
{
"type": "mrkdwn",
"text": "Hello, world!"
}
]
}

Actions Block
An actions block holds a row of interactive elements, such as buttons, select menus, overflow menus, checkboxes, and date pickers.
Required: elements (up to 25 elements).
- slackblocks
- JSON
- Slack UI
from slackblocks import ActionsBlock, CheckboxGroup, Option
ActionsBlock(
block_id="fake_block_id",
elements=CheckboxGroup(
action_id="actionId-0",
options=[
Option(text="*a*", value="a", description="*a*"),
Option(text="*b*", value="b", description="*b*"),
Option(text="*c*", value="c", description="*c*"),
],
),
)
import { ActionsBlock, Checkboxes, Markdown, Option, PlainText } from "@nicklambourne/slackblocks";
ActionsBlock()
.blockId("fake_block_id")
.elements(
Checkboxes()
.actionId("actionId-0")
.options(
["a", "b", "c"].map((value) =>
Option()
.text(Markdown().text(`*${value}*`))
.value(value)
.description(PlainText().text(`*${value}*`)),
),
),
)
.build();
block, err := slackblocks.NewActionsBlock().
BlockID("fake_block_id").
Elements(
slackblocks.NewCheckboxes().
ActionID("actionId-0").
Options(
slackblocks.NewOption().TextObject(slackblocks.NewMarkdown().Text("*a*")).Value("a").Description("*a*"),
slackblocks.NewOption().TextObject(slackblocks.NewMarkdown().Text("*b*")).Value("b").Description("*b*"),
slackblocks.NewOption().TextObject(slackblocks.NewMarkdown().Text("*c*")).Value("c").Description("*c*"),
),
).
Build()
ActionsBlock block = ActionsBlock.builder()
.blockId("fake_block_id")
.elements(CheckboxesElement.builder()
.actionId("actionId-0")
.options(
Option.builder().text(MarkdownText.of("*a*")).value("a").description("*a*").build(),
Option.builder().text(MarkdownText.of("*b*")).value("b").description("*b*").build(),
Option.builder().text(MarkdownText.of("*c*")).value("c").description("*c*").build())
.build())
.build();
var block = new ActionsBlock(
elements: [
new CheckboxesElement(
"actionId-0",
options: [
new Option(new MarkdownText("*a*"), "a", description: "*a*"),
new Option(new MarkdownText("*b*"), "b", description: "*b*"),
new Option(new MarkdownText("*c*"), "c", description: "*c*"),
]),
],
blockId: "fake_block_id");
require "slackblocks"
include Slackblocks
block = ActionsBlock.new(
elements: [
CheckboxesElement.new(
action_id: "actionId-0",
options: [
Option.new(
text: MarkdownText.new(text: "*a*"),
value: "a",
description: PlainText.new(text: "*a*")
),
Option.new(
text: MarkdownText.new(text: "*b*"),
value: "b",
description: PlainText.new(text: "*b*")
),
Option.new(
text: MarkdownText.new(text: "*c*"),
value: "c",
description: PlainText.new(text: "*c*")
)
]
)
],
block_id: "fake_block_id"
)
puts block.to_json
{
"type": "actions",
"block_id": "fake_block_id",
"elements": [
{
"type": "checkboxes",
"action_id": "actionId-0",
"options": [
{
"text": {
"type": "mrkdwn",
"text": "*a*"
},
"value": "a",
"description": {
"type": "plain_text",
"text": "*a*"
}
},
{
"text": {
"type": "mrkdwn",
"text": "*b*"
},
"value": "b",
"description": {
"type": "plain_text",
"text": "*b*"
}
},
{
"text": {
"type": "mrkdwn",
"text": "*c*"
},
"value": "c",
"description": {
"type": "plain_text",
"text": "*c*"
}
}
]
}
]
}

Table Block
A table block lays out raw text and rich text cells in rows and columns. Optional column_settings control each column's alignment and whether its text wraps.
Required: rows. Every row must have the same number of cells, and column_settings needs one entry for every column.
- slackblocks
- JSON
- Slack UI
from slackblocks import (
ColumnSettings,
RawText,
RichText,
RichTextLink,
RichTextSection,
TableBlock,
)
TableBlock(
block_id="fake_block_id",
column_settings=[
ColumnSettings(align="right", is_wrapped=True),
ColumnSettings(align="left"),
],
rows=[
[
RichTextSection(
elements=[RichText(text="Header 1", bold=True)],
),
RichTextSection(
elements=[RichText(text="Header 2", bold=True)],
),
],
[
RawText(text="Datum 1"),
RichTextSection(
elements=[
RichTextLink(
url="https://slack.com",
text="Datum 2",
)
],
),
],
],
)
import {
ColumnSettings,
RawText,
RichText,
RichTextBlock,
RichTextLink,
RichTextSection,
TableBlock,
} from "@nicklambourne/slackblocks";
TableBlock()
.blockId("fake_block_id")
.columnSettings(
ColumnSettings().align("right").isWrapped(true),
ColumnSettings().align("left"),
)
.rows([
RichTextBlock().elements(
RichTextSection().elements(RichText().text("Header 1").style({ bold: true })),
),
RichTextBlock().elements(
RichTextSection().elements(RichText().text("Header 2").style({ bold: true })),
),
])
.rows([
RawText().text("Datum 1"),
RichTextBlock().elements(
RichTextSection().elements(
RichTextLink().url("https://slack.com").text("Datum 2"),
),
),
])
.build();
block, err := slackblocks.NewTableBlock().
BlockID("fake_block_id").
ColumnSettings(
slackblocks.NewColumnSettings().Align("right").IsWrapped(true),
slackblocks.NewColumnSettings().Align("left"),
).
Rows(
[]slackblocks.TableCell{
slackblocks.NewRichTextBlock().Elements(
slackblocks.NewRichTextSection().Elements(
slackblocks.NewRichText().Text("Header 1").Style(slackblocks.RichTextStyle{"bold": true}),
),
),
slackblocks.NewRichTextBlock().Elements(
slackblocks.NewRichTextSection().Elements(
slackblocks.NewRichText().Text("Header 2").Style(slackblocks.RichTextStyle{"bold": true}),
),
),
},
[]slackblocks.TableCell{
slackblocks.NewRawText().Text("Datum 1"),
slackblocks.NewRichTextBlock().Elements(
slackblocks.NewRichTextSection().Elements(
slackblocks.NewRichTextLink().URL("https://slack.com").Text("Datum 2"),
),
),
},
).
Build()
TableBlock block = TableBlock.builder()
.blockId("fake_block_id")
.columnSettings(
ColumnSettings.builder().align(ColumnAlign.RIGHT).isWrapped(true).build(),
ColumnSettings.builder().align(ColumnAlign.LEFT).build())
.rows(
List.of(
RichTextBlock.builder().elements(RichTextSection.builder()
.elements(RichTextText.builder().text("Header 1")
.bold(true).build()).build()).build(),
RichTextBlock.builder().elements(RichTextSection.builder()
.elements(RichTextText.builder().text("Header 2")
.bold(true).build()).build()).build()),
List.of(
RawText.builder().text("Datum 1").build(),
RichTextBlock.builder().elements(RichTextSection.builder()
.elements(RichTextLink.builder().url("https://slack.com").text("Datum 2").build())
.build()).build()))
.build();
var block = new TableBlock(
rows: [
[
new RichTextBlock(
elements: [
new RichTextSection(
elements: [
new RichTextText(
"Header 1",
style: new RichTextStyle(bold: true)),
]),
]),
new RichTextBlock(
elements: [
new RichTextSection(
elements: [
new RichTextText(
"Header 2",
style: new RichTextStyle(bold: true)),
]),
]),
],
[
new RawText("Datum 1"),
new RichTextBlock(
elements: [
new RichTextSection(
elements: [new RichTextLink("https://slack.com", text: "Datum 2")]),
]),
],
],
columnSettings: [
new ColumnSettings(align: ColumnAlign.Right, isWrapped: true),
new ColumnSettings(align: ColumnAlign.Left),
],
blockId: "fake_block_id");
require "slackblocks"
include Slackblocks
block = TableBlock.new(
rows: [
[
RichTextBlock.new(
elements: [
RichTextSection.new(
elements: [RichTextText.new(text: "Header 1", style: RichTextStyle.new(bold: true))]
)
]
),
RichTextBlock.new(
elements: [
RichTextSection.new(
elements: [RichTextText.new(text: "Header 2", style: RichTextStyle.new(bold: true))]
)
]
)
],
[
RawText.new(text: "Datum 1"),
RichTextBlock.new(
elements: [
RichTextSection.new(elements: [RichTextLink.new(url: "https://slack.com", text: "Datum 2")])
]
)
]
],
column_settings: [ColumnSettings.new(align: :right, is_wrapped: true), ColumnSettings.new(align: :left)],
block_id: "fake_block_id"
)
puts block.to_json
{
"type": "table",
"block_id": "fake_block_id",
"rows": [
[
{
"type": "rich_text",
"elements": [
{
"type": "rich_text_section",
"elements": [
{
"type": "text",
"text": "Header 1",
"style": {
"bold": true
}
}
]
}
]
},
{
"type": "rich_text",
"elements": [
{
"type": "rich_text_section",
"elements": [
{
"type": "text",
"text": "Header 2",
"style": {
"bold": true
}
}
]
}
]
}
],
[
{
"type": "raw_text",
"text": "Datum 1"
},
{
"type": "rich_text",
"elements": [
{
"type": "rich_text_section",
"elements": [
{
"type": "link",
"url": "https://slack.com",
"text": "Datum 2"
}
]
}
]
}
]
],
"column_settings": [
{
"align": "right",
"is_wrapped": true
},
{
"align": "left"
}
]
}

Video Block
Embeds a video from a Slack-supported provider such as YouTube or Vimeo. Plain strings supplied for title and description are converted to Slack plain_text objects automatically.
Required: alt_text, thumbnail_url, title, video_url. Slack restricts which domains may be embedded — supplying an unsupported URL will produce a Slack API error rather than an InvalidUsageError at construction.
- slackblocks
- JSON
- Slack UI
from slackblocks import VideoBlock
VideoBlock(
alt_text="Use the Events API to create a dynamic App Home",
block_id="fake_block_id",
thumbnail_url="https://i.ytimg.com/vi/8876OZV_Yy0/hqdefault.jpg",
title="Use the Events API to create a dynamic App Home",
video_url="https://www.youtube.com/embed/8876OZV_Yy0?feature=oembed&autoplay=1",
description="Slack sure is nifty!",
title_url="https://www.youtube.com/watch?v=8876OZV_Yy0",
)
import { VideoBlock } from "@nicklambourne/slackblocks";
VideoBlock()
.altText("Use the Events API to create a dynamic App Home")
.blockId("fake_block_id")
.thumbnailUrl("https://i.ytimg.com/vi/8876OZV_Yy0/hqdefault.jpg")
.title("Use the Events API to create a dynamic App Home")
.videoUrl("https://www.youtube.com/embed/8876OZV_Yy0?feature=oembed&autoplay=1")
.description("Slack sure is nifty!")
.titleUrl("https://www.youtube.com/watch?v=8876OZV_Yy0")
.build();
block, err := slackblocks.NewVideoBlock().
AltText("Use the Events API to create a dynamic App Home").
BlockID("fake_block_id").
ThumbnailURL("https://i.ytimg.com/vi/8876OZV_Yy0/hqdefault.jpg").
Title("Use the Events API to create a dynamic App Home").
VideoURL("https://www.youtube.com/embed/8876OZV_Yy0?feature=oembed&autoplay=1").
Description("Slack sure is nifty!").
TitleURL("https://www.youtube.com/watch?v=8876OZV_Yy0").
Build()
VideoBlock block = VideoBlock.builder()
.altText("Use the Events API to create a dynamic App Home")
.blockId("fake_block_id")
.thumbnailUrl("https://i.ytimg.com/vi/8876OZV_Yy0/hqdefault.jpg")
.title("Use the Events API to create a dynamic App Home")
.videoUrl("https://www.youtube.com/embed/8876OZV_Yy0?feature=oembed&autoplay=1")
.description("Slack sure is nifty!")
.titleUrl("https://www.youtube.com/watch?v=8876OZV_Yy0")
.build();
var block = new VideoBlock(
altText: "Use the Events API to create a dynamic App Home",
thumbnailUrl: "https://i.ytimg.com/vi/8876OZV_Yy0/hqdefault.jpg",
title: "Use the Events API to create a dynamic App Home",
videoUrl: "https://www.youtube.com/embed/8876OZV_Yy0?feature=oembed&autoplay=1",
description: "Slack sure is nifty!",
titleUrl: "https://www.youtube.com/watch?v=8876OZV_Yy0",
blockId: "fake_block_id");
require "slackblocks"
include Slackblocks
block = VideoBlock.new(
alt_text: "Use the Events API to create a dynamic App Home",
thumbnail_url: "https://i.ytimg.com/vi/8876OZV_Yy0/hqdefault.jpg",
title: PlainText.new(text: "Use the Events API to create a dynamic App Home"),
video_url: "https://www.youtube.com/embed/8876OZV_Yy0?feature=oembed&autoplay=1",
block_id: "fake_block_id",
description: PlainText.new(text: "Slack sure is nifty!"),
title_url: "https://www.youtube.com/watch?v=8876OZV_Yy0"
)
puts block.to_json
{
"type": "video",
"block_id": "fake_block_id",
"alt_text": "Use the Events API to create a dynamic App Home",
"thumbnail_url": "https://i.ytimg.com/vi/8876OZV_Yy0/hqdefault.jpg",
"title": {
"type": "plain_text",
"text": "Use the Events API to create a dynamic App Home"
},
"video_url": "https://www.youtube.com/embed/8876OZV_Yy0?feature=oembed&autoplay=1",
"description": {
"type": "plain_text",
"text": "Slack sure is nifty!"
},
"title_url": "https://www.youtube.com/watch?v=8876OZV_Yy0"
}

See the Slack reference for the full list of optional fields and provider requirements.
Alert Block
Alerts add a severity-labelled notice to a modal.
Required: text (up to 200 characters). level sets the severity: default, info, warning, error, or success.
- slackblocks
- JSON
- Slack UI
from slackblocks import AlertBlock
AlertBlock(
"The deployment needs attention.",
level="warning",
block_id="fake_block_id",
)
import { AlertBlock } from "@nicklambourne/slackblocks";
AlertBlock()
.text("The deployment needs attention.")
.level("warning")
.blockId("fake_block_id")
.build();
block, err := slackblocks.NewAlertBlock().
Text("The deployment needs attention.").
Level("warning").
BlockID("fake_block_id").
Build()
AlertBlock block = AlertBlock.builder()
.text("The deployment needs attention.")
.level(AlertLevel.WARNING)
.blockId("fake_block_id")
.build();
var block = new AlertBlock(
"The deployment needs attention.",
level: AlertLevel.Warning,
blockId: "fake_block_id");
require "slackblocks"
include Slackblocks
block = AlertBlock.new(
text: MarkdownText.new(text: "The deployment needs attention."),
level: :warning,
block_id: "fake_block_id"
)
puts block.to_json
{
"type": "alert",
"block_id": "fake_block_id",
"text": {
"type": "mrkdwn",
"text": "The deployment needs attention."
},
"level": "warning"
}

Card Block
Cards combine text, images, Slack-provided icons, and up to three buttons in a compact panel.
Provide at least one of hero_image, title, actions, or body. An image icon and a slack_icon cannot be combined.
- slackblocks
- JSON
- Slack UI
from slackblocks import Button, CardBlock, SlackIcon
CardBlock(
title="Build complete",
body="Version 2.1.0 is ready to deploy.",
slack_icon=SlackIcon("rocket"),
actions=Button("Open build", "open_build"),
block_id="fake_block_id",
)
import { Button, CardBlock, SlackIcon } from "@nicklambourne/slackblocks";
CardBlock()
.title("Build complete")
.body("Version 2.1.0 is ready to deploy.")
.slackIcon(SlackIcon().name("rocket"))
.actions(Button().text("Open build").actionId("open_build"))
.blockId("fake_block_id")
.build();
block, err := slackblocks.NewCardBlock().
Title("Build complete").
Body("Version 2.1.0 is ready to deploy.").
SlackIcon(slackblocks.NewSlackIcon().Name("rocket")).
Actions(slackblocks.NewButton().Text("Open build").ActionID("open_build")).
BlockID("fake_block_id").
Build()
CardBlock block = CardBlock.builder()
.title("Build complete")
.body("Version 2.1.0 is ready to deploy.")
.slackIcon(SlackIcon.builder().name("rocket").build())
.actions(ButtonElement.builder().text("Open build").actionId("open_build").build())
.blockId("fake_block_id")
.build();
var block = new CardBlock(
title: "Build complete",
body: "Version 2.1.0 is ready to deploy.",
actions: [new ButtonElement("Open build", "open_build")],
slackIcon: new SlackIcon(name: "rocket"),
blockId: "fake_block_id");
require "slackblocks"
include Slackblocks
block = CardBlock.new(
title: MarkdownText.new(text: "Build complete"),
body: MarkdownText.new(text: "Version 2.1.0 is ready to deploy."),
actions: [ButtonElement.new(text: PlainText.new(text: "Open build"), action_id: "open_build")],
slack_icon: SlackIcon.new(name: "rocket"),
block_id: "fake_block_id"
)
puts block.to_json
{
"type": "card",
"block_id": "fake_block_id",
"title": {
"type": "mrkdwn",
"text": "Build complete"
},
"body": {
"type": "mrkdwn",
"text": "Version 2.1.0 is ready to deploy."
},
"actions": [
{
"type": "button",
"text": {
"type": "plain_text",
"text": "Open build"
},
"action_id": "open_build"
}
],
"slack_icon": {
"type": "icon",
"name": "rocket"
}
}

Carousel Block
A carousel presents between one and ten cards in a horizontally scrolling collection.
Required: elements.
- slackblocks
- JSON
- Slack UI
from slackblocks import CardBlock, CarouselBlock
CarouselBlock([
CardBlock(title="First result", block_id="card_1"),
CardBlock(title="Second result", block_id="card_2"),
], block_id="fake_block_id")
import { CardBlock, CarouselBlock } from "@nicklambourne/slackblocks";
CarouselBlock()
.elements(
CardBlock().title("First result").blockId("card_1"),
CardBlock().title("Second result").blockId("card_2"),
)
.blockId("fake_block_id")
.build();
block, err := slackblocks.NewCarouselBlock().
Elements(
slackblocks.NewCardBlock().Title("First result").BlockID("card_1"),
slackblocks.NewCardBlock().Title("Second result").BlockID("card_2"),
).
BlockID("fake_block_id").
Build()
CarouselBlock block = CarouselBlock.builder()
.elements(
CardBlock.builder().title("First result").blockId("card_1").build(),
CardBlock.builder().title("Second result").blockId("card_2").build())
.blockId("fake_block_id")
.build();
var block = new CarouselBlock(
elements: [
new CardBlock(title: "First result", blockId: "card_1"),
new CardBlock(title: "Second result", blockId: "card_2"),
],
blockId: "fake_block_id");
require "slackblocks"
include Slackblocks
block = CarouselBlock.new(
elements: [
CardBlock.new(title: MarkdownText.new(text: "First result"), block_id: "card_1"),
CardBlock.new(title: MarkdownText.new(text: "Second result"), block_id: "card_2")
],
block_id: "fake_block_id"
)
puts block.to_json
{
"type": "carousel",
"block_id": "fake_block_id",
"elements": [
{
"type": "card",
"block_id": "card_1",
"title": {
"type": "mrkdwn",
"text": "First result"
}
},
{
"type": "card",
"block_id": "card_2",
"title": {
"type": "mrkdwn",
"text": "Second result"
}
}
]
}

Container Block
Containers group up to ten related child blocks under a plain-text or rich-text title.
Required: child_blocks, plus either title or rich_text_title.
- slackblocks
- JSON
- Slack UI
from slackblocks import ContainerBlock, SectionBlock
ContainerBlock(
title="Deployment summary",
child_blocks=[
SectionBlock("All systems operational.", block_id="child_1"),
],
has_header_divider=True,
block_id="fake_block_id",
)
import { ContainerBlock, SectionBlock } from "@nicklambourne/slackblocks";
ContainerBlock()
.title("Deployment summary")
.childBlocks(
SectionBlock().text("All systems operational.").blockId("child_1"),
)
.width("standard")
.isCollapsible(false)
.defaultCollapsed(false)
.hasHeaderDivider(true)
.blockId("fake_block_id")
.build();
block, err := slackblocks.NewContainerBlock().
Title("Deployment summary").
ChildBlocks(slackblocks.NewSectionBlock().Text("All systems operational.").BlockID("child_1")).
Width("standard").
IsCollapsible(false).
DefaultCollapsed(false).
HasHeaderDivider(true).
BlockID("fake_block_id").
Build()
ContainerBlock block = ContainerBlock.builder()
.title("Deployment summary")
.childBlocks(SectionBlock.builder()
.markdownText("All systems operational.").blockId("child_1").build())
.width(ContainerWidth.STANDARD)
.isCollapsible(false)
.defaultCollapsed(false)
.hasHeaderDivider(true)
.blockId("fake_block_id")
.build();
var block = new ContainerBlock(
childBlocks: [new SectionBlock(text: "All systems operational.", blockId: "child_1")],
title: "Deployment summary",
width: ContainerWidth.Standard,
isCollapsible: false,
defaultCollapsed: false,
hasHeaderDivider: true,
blockId: "fake_block_id");
require "slackblocks"
include Slackblocks
block = ContainerBlock.new(
child_blocks: [SectionBlock.new(text: MarkdownText.new(text: "All systems operational."), block_id: "child_1")],
title: PlainText.new(text: "Deployment summary"),
width: :standard,
is_collapsible: false,
default_collapsed: false,
has_header_divider: true,
block_id: "fake_block_id"
)
puts block.to_json
{
"type": "container",
"block_id": "fake_block_id",
"title": {
"type": "plain_text",
"text": "Deployment summary"
},
"child_blocks": [
{
"type": "section",
"block_id": "child_1",
"text": {
"type": "mrkdwn",
"text": "All systems operational."
}
}
],
"width": "standard",
"is_collapsible": false,
"default_collapsed": false,
"has_header_divider": true
}

Context Actions Block
Context actions hold feedback controls or compact icon buttons. Slack currently offers the trash icon for icon buttons.
Required: elements (up to 5).
- slackblocks
- JSON
- Slack UI
from slackblocks import ContextActionsBlock, FeedbackButton, FeedbackButtons
ContextActionsBlock([
FeedbackButtons(
positive_button=FeedbackButton("Good", "positive"),
negative_button=FeedbackButton("Bad", "negative"),
action_id="response_feedback",
)
], block_id="fake_block_id")
import { ContextActionsBlock, FeedbackButton, FeedbackButtons } from "@nicklambourne/slackblocks";
ContextActionsBlock()
.elements(
FeedbackButtons()
.actionId("response_feedback")
.positiveButton(FeedbackButton().text("Good").value("positive"))
.negativeButton(FeedbackButton().text("Bad").value("negative")),
)
.blockId("fake_block_id")
.build();
block, err := slackblocks.NewContextActionsBlock().
Elements(
slackblocks.NewFeedbackButtons().
ActionID("response_feedback").
PositiveButton(slackblocks.NewFeedbackButton().Text("Good").Value("positive")).
NegativeButton(slackblocks.NewFeedbackButton().Text("Bad").Value("negative")),
).
BlockID("fake_block_id").
Build()
ContextActionsBlock block = ContextActionsBlock.builder()
.elements(FeedbackButtonsElement.builder()
.actionId("response_feedback")
.positiveButton(FeedbackButton.builder().plainText("Good").value("positive").build())
.negativeButton(FeedbackButton.builder().plainText("Bad").value("negative").build())
.build())
.blockId("fake_block_id")
.build();
var block = new ContextActionsBlock(
elements: [
new FeedbackButtonsElement(
positiveButton: new FeedbackButton("Good", "positive"),
negativeButton: new FeedbackButton("Bad", "negative"),
actionId: "response_feedback"),
],
blockId: "fake_block_id");
require "slackblocks"
include Slackblocks
block = ContextActionsBlock.new(
elements: [
FeedbackButtonsElement.new(
positive_button: FeedbackButton.new(text: PlainText.new(text: "Good"), value: "positive"),
negative_button: FeedbackButton.new(text: PlainText.new(text: "Bad"), value: "negative"),
action_id: "response_feedback"
)
],
block_id: "fake_block_id"
)
puts block.to_json
{
"type": "context_actions",
"block_id": "fake_block_id",
"elements": [
{
"type": "feedback_buttons",
"positive_button": {
"text": {
"type": "plain_text",
"text": "Good"
},
"value": "positive"
},
"negative_button": {
"text": {
"type": "plain_text",
"text": "Bad"
},
"value": "negative"
},
"action_id": "response_feedback"
}
]
}

Data Table Block
Data tables support raw text, sortable raw numbers, and rich-text body cells. They require a header plus at least one data row.
Required: rows and caption. Tables hold up to 200 data rows, every row must have the same number of cells, and all cell text together is limited to 20,000 characters.
- slackblocks
- JSON
- Slack UI
from slackblocks import DataTableBlock, RawNumber, RawText
DataTableBlock(
caption="Team scores",
rows=[
[RawText("Name"), RawText("Score")],
[RawText("Alice"), RawNumber(42, "42")],
],
block_id="fake_block_id",
)
import { DataTableBlock, RawNumber, RawText } from "@nicklambourne/slackblocks";
DataTableBlock()
.caption("Team scores")
.rows([RawText().text("Name"), RawText().text("Score")])
.rows([RawText().text("Alice"), RawNumber().value(42).text("42")])
.blockId("fake_block_id")
.build();
block, err := slackblocks.NewDataTableBlock().
Caption("Team scores").
Rows(
[]slackblocks.DataTableCell{slackblocks.NewRawText().Text("Name"), slackblocks.NewRawText().Text("Score")},
[]slackblocks.DataTableCell{slackblocks.NewRawText().Text("Alice"), slackblocks.NewRawNumber().Value(42).Text("42")},
).
BlockID("fake_block_id").
Build()
DataTableBlock block = DataTableBlock.builder()
.caption("Team scores")
.rows(
List.of(RawText.builder().text("Name").build(), RawText.builder().text("Score").build()),
List.of(RawText.builder().text("Alice").build(),
RawNumber.builder().value(42).text("42").build()))
.blockId("fake_block_id")
.build();
var block = new DataTableBlock(
rows: [
[new RawText("Name"), new RawText("Score")],
[new RawText("Alice"), new RawNumber(42, "42")],
],
caption: "Team scores",
blockId: "fake_block_id");
require "slackblocks"
include Slackblocks
block = DataTableBlock.new(
rows: [
[RawText.new(text: "Name"), RawText.new(text: "Score")],
[RawText.new(text: "Alice"), RawNumber.new(value: 42, text: "42")]
],
caption: "Team scores",
page_size: 5,
row_header_column_index: 0,
block_id: "fake_block_id"
)
puts block.to_json
{
"type": "data_table",
"block_id": "fake_block_id",
"rows": [
[
{
"type": "raw_text",
"text": "Name"
},
{
"type": "raw_text",
"text": "Score"
}
],
[
{
"type": "raw_text",
"text": "Alice"
},
{
"type": "raw_number",
"value": 42,
"text": "42"
}
]
],
"page_size": 5,
"caption": "Team scores",
"row_header_column_index": 0
}

Data Visualization Block
Slack can render pie charts or axis-based bar, area, and line charts directly from Block Kit data.
Required: title (up to 50 characters) and chart.
- slackblocks
- JSON
- Slack UI
from slackblocks import ChartSegment, DataVisualizationBlock, PieChart
DataVisualizationBlock(
title="Incidents by severity",
chart=PieChart([
ChartSegment("High", 3),
ChartSegment("Low", 12),
]),
block_id="fake_block_id",
)
import { ChartSegment, DataVisualizationBlock, PieChart } from "@nicklambourne/slackblocks";
DataVisualizationBlock()
.title("Incidents by severity")
.chart(
PieChart().segments(
ChartSegment().label("High").value(3),
ChartSegment().label("Low").value(12),
),
)
.blockId("fake_block_id")
.build();
block, err := slackblocks.NewDataVisualizationBlock().
Title("Incidents by severity").
Chart(
slackblocks.NewPieChart().Segments(
slackblocks.NewChartSegment().Label("High").Value(3),
slackblocks.NewChartSegment().Label("Low").Value(12),
),
).
BlockID("fake_block_id").
Build()
DataVisualizationBlock block = DataVisualizationBlock.builder()
.title("Incidents by severity")
.chart(PieChart.builder()
.segments(
ChartSegment.builder().label("High").value(3).build(),
ChartSegment.builder().label("Low").value(12).build())
.build())
.blockId("fake_block_id")
.build();
var block = new DataVisualizationBlock(
"Incidents by severity",
chart: new PieChart(segments: [new ChartSegment("High", 3), new ChartSegment("Low", 12)]),
blockId: "fake_block_id");
require "slackblocks"
include Slackblocks
block = DataVisualizationBlock.new(
title: "Incidents by severity",
chart: PieChart.new(
segments: [ChartSegment.new(label: "High", value: 3), ChartSegment.new(label: "Low", value: 12)]
),
block_id: "fake_block_id"
)
puts block.to_json
{
"type": "data_visualization",
"block_id": "fake_block_id",
"title": "Incidents by severity",
"chart": {
"type": "pie",
"segments": [
{
"label": "High",
"value": 3
},
{
"label": "Low",
"value": 12
}
]
}
}

Task Card Block
Task cards show a task's state, optional rich-text details or output, and the URL sources used to produce it.
Required: task_id and title.
- slackblocks
- JSON
- Slack UI
from slackblocks import TaskCardBlock, URLSource
TaskCardBlock(
task_id="weather_1",
title="Fetch weather data",
status="complete",
sources=[URLSource("https://weather.com/", "weather.com")],
block_id="fake_block_id",
)
import { TaskCardBlock, UrlSource } from "@nicklambourne/slackblocks";
TaskCardBlock()
.taskId("weather_1")
.title("Fetch weather data")
.status("complete")
.sources(UrlSource().url("https://weather.com/").text("weather.com"))
.blockId("fake_block_id")
.build();
block, err := slackblocks.NewTaskCardBlock().
TaskID("weather_1").
Title("Fetch weather data").
Status("complete").
Sources(slackblocks.NewURLSource().URL("https://weather.com/").Text("weather.com")).
BlockID("fake_block_id").
Build()
TaskCardBlock block = TaskCardBlock.builder()
.taskId("weather_1")
.title("Fetch weather data")
.status(TaskStatus.COMPLETE)
.sources(UrlSource.builder().url("https://weather.com/").text("weather.com").build())
.blockId("fake_block_id")
.build();
var block = new TaskCardBlock(
"weather_1",
"Fetch weather data",
sources: [new UrlSource("https://weather.com/", "weather.com")],
status: TaskCardStatus.Complete,
blockId: "fake_block_id");
require "slackblocks"
include Slackblocks
block = TaskCardBlock.new(
task_id: "weather_1",
title: "Fetch weather data",
sources: [UrlSource.new(url: "https://weather.com/", text: "weather.com")],
status: :complete,
block_id: "fake_block_id"
)
puts block.to_json
{
"type": "task_card",
"block_id": "fake_block_id",
"task_id": "weather_1",
"title": "Fetch weather data",
"sources": [
{
"type": "url",
"url": "https://weather.com/",
"text": "weather.com"
}
],
"status": "complete"
}

Plan Block
A plan groups task cards. slackblocks automatically renders nested tasks in Slack's plan-specific wire format.
Required: title.
- slackblocks
- JSON
- Slack UI
from slackblocks import PlanBlock, TaskCardBlock
PlanBlock(
title="Release plan",
tasks=[
TaskCardBlock("test", "Run the test suite", status="complete"),
TaskCardBlock("deploy", "Deploy the release", status="pending"),
],
block_id="fake_block_id",
)
import { PlanBlock, TaskCardBlock } from "@nicklambourne/slackblocks";
PlanBlock()
.title("Release plan")
.tasks(
TaskCardBlock().taskId("test").title("Run the test suite").status("complete"),
TaskCardBlock().taskId("deploy").title("Deploy the release").status("pending"),
)
.blockId("fake_block_id")
.build();
block, err := slackblocks.NewPlanBlock().
Title("Release plan").
Tasks(
slackblocks.NewTaskCardBlock().TaskID("test").Title("Run the test suite").Status("complete"),
slackblocks.NewTaskCardBlock().TaskID("deploy").Title("Deploy the release").Status("pending"),
).
BlockID("fake_block_id").
Build()
PlanBlock block = PlanBlock.builder()
.title("Release plan")
.tasks(
TaskCardBlock.builder().taskId("test").title("Run the test suite").status(TaskStatus.COMPLETE).build(),
TaskCardBlock.builder().taskId("deploy").title("Deploy the release").status(TaskStatus.PENDING).build())
.blockId("fake_block_id")
.build();
var block = new PlanBlock(
"Release plan",
tasks: [
new TaskCardBlock("test", "Run the test suite", status: TaskCardStatus.Complete),
new TaskCardBlock("deploy", "Deploy the release", status: TaskCardStatus.Pending),
],
blockId: "fake_block_id");
require "slackblocks"
include Slackblocks
block = PlanBlock.new(
title: "Release plan",
tasks: [
TaskCardBlock.new(task_id: "test", title: "Run the test suite", status: :complete),
TaskCardBlock.new(task_id: "deploy", title: "Deploy the release", status: :pending)
],
block_id: "fake_block_id"
)
puts block.to_json
{
"type": "plan",
"block_id": "fake_block_id",
"title": "Release plan",
"tasks": [
{
"task_id": "test",
"title": "Run the test suite",
"status": "complete"
},
{
"task_id": "deploy",
"title": "Deploy the release",
"status": "pending"
}
]
}

Higher-Level Components
Components package common layout behavior while still producing ordinary Block Kit
blocks. Pass them directly to a fluent collection setter such as Message().blocks();
the parent expands the component when you call .build().
Paginator
Paginator() selects one page of content and adds standard context and actions blocks
for navigation. Its previous and next button values contain the one-based page number
your interaction handler should render next.
import { Message, Paginator, SectionBlock } from "@nicklambourne/slackblocks";
const payload = Message()
.channel("C01234567")
.text("Search results")
.blocks(
Paginator()
.blocks(
SectionBlock().text("Result one"),
SectionBlock().text("Result two"),
SectionBlock().text("Result three"),
)
.actionIdPrefix("search-results")
.page(1)
.pageSize(2),
)
.build();
The component is deliberately state-free: your Slack action handler reads the button value, creates the same paginator with that page, and updates the message.
Accordion
Accordion() expands into Slack-native collapsible container blocks, so expanding and
collapsing sections does not require an application-side interaction handler.
import {
Accordion,
AccordionSection,
Message,
SectionBlock,
} from "@nicklambourne/slackblocks";
const payload = Message()
.channel("C01234567")
.text("Deployment details")
.blocks(
Accordion().sections(
AccordionSection()
.title("Summary")
.expanded(true)
.blocks(SectionBlock().text("Version 2.2.0 is ready.")),
AccordionSection()
.title("Checks")
.blocks(SectionBlock().text("All required checks passed.")),
),
)
.build();
See Components for every setter and validation rule.
Higher-Level Components
Components expand to ordinary slack.Block values. Call SlackBlocks() and pass the
result straight to slack.MsgOptionBlocks; use BuildMany() only when composing a raw
JSON payload.
Paginator
blocks, err := slackblocks.NewPaginator().
Blocks(
slackblocks.NewSectionBlock().Text("Result one"),
slackblocks.NewSectionBlock().Text("Result two"),
slackblocks.NewSectionBlock().Text("Result three"),
).
ActionIDPrefix("search-results").
Page(1).
PageSize(2).
SlackBlocks()
if err == nil {
_, _, err = client.PostMessageContext(
ctx,
"C01234567",
slack.MsgOptionText("Search results", false),
slack.MsgOptionBlocks(blocks...),
)
}
The previous and next button values contain the one-based page for your action handler to render.
Accordion
blocks, err := slackblocks.NewAccordion().Sections(
slackblocks.NewAccordionSection().
Title("Summary").
Expanded(true).
Blocks(slackblocks.NewSectionBlock().Text("Version 2.2.0 is ready.")),
slackblocks.NewAccordionSection().
Title("Checks").
Blocks(slackblocks.NewSectionBlock().Text("All required checks passed.")),
).SlackBlocks()
if err == nil {
_, _, err = client.PostMessageContext(
ctx,
"C01234567",
slack.MsgOptionText("Deployment details", false),
slack.MsgOptionBlocks(blocks...),
)
}
Accordion sections use Slack-native collapsible containers and need no application-side expansion handler. See Components for the complete API.
Higher-Level Components
Components expand to ordinary immutable Block values. Pass those values directly to the official Slack Java SDK, just like a single block.
Paginator
List<Block> blocks = Paginator.builder("search-results")
.blocks(
SectionBlock.builder().markdownText("Result one").build(),
SectionBlock.builder().markdownText("Result two").build(),
SectionBlock.builder().markdownText("Result three").build())
.page(1)
.pageSize(2)
.build();
ChatPostMessageRequest request = ChatPostMessageRequest.builder()
.channel("C01234567")
.text("Search results")
.blocks(List.copyOf(blocks))
.build();
The previous and next button values contain the one-based page for your action handler to render.
Accordion
List<Block> blocks = Accordion.builder()
.sections(
AccordionSection.builder("Summary")
.expanded(true)
.blocks(SectionBlock.builder().markdownText("Version 2.2.0 is ready.").build())
.build(),
AccordionSection.builder("Checks")
.blocks(SectionBlock.builder().markdownText("All required checks passed.").build())
.build())
.build();
ChatPostMessageRequest request = ChatPostMessageRequest.builder()
.channel("C01234567")
.text("Deployment details")
.blocks(List.copyOf(blocks))
.build();
Accordion sections use Slack-native collapsible containers and need no application-side expansion handler. See Components for the complete API.
Higher-Level Components
Components return ordinary IBlock values. Spread them into any block collection, just like a single block.
Paginator
var blocks = Paginator.Create(
"search-results",
[
new SectionBlock(text: "Result one"),
new SectionBlock(text: "Result two"),
new SectionBlock(text: "Result three"),
],
page: 1,
pageSize: 2);
var message = new MessagePayload("C01234567", text: "Search results", blocks: [.. blocks]);
The previous and next button values contain the one-based page for your action handler to render.
Accordion
var blocks = Accordion.Create([
AccordionSection.Create("Summary", [new SectionBlock(text: "Version 2.2.0 is ready.")], expanded: true),
AccordionSection.Create("Checks", [new SectionBlock(text: "All required checks passed.")]),
]);
var message = new MessagePayload("C01234567", text: "Deployment details", blocks: [.. blocks]);
Accordion sections use Slack-native collapsible containers and need no application-side expansion handler. See Components for the complete API.
require "slackblocks"
include Slackblocks
block = PlanBlock.new(title: "Release plan", tasks: [TaskCardBlock.new(task_id: "task-1", title: "Run checks", status: :complete)])
puts block.to_json