Skip to main content

Layouts

From 3.2.0, a layout block groups native blocks into one to five rows, each containing one to three items. Each item wraps one block and controls its share of the row's width.

Anatomy of a layout​

A layout contains a label and a row. The row contains two items: a wide item wrapping the API section and a narrow item wrapping the Healthy section. A separate fallback section reads API: Healthy.

Build from the inside out: create the child blocks, wrap each in an item, collect the items into a row, then put the row in the layout. The diagram shows the object structure; its nested outlines are annotations, not Slack grid lines.

Basic example​

This example places API beside Healthy in one row. The wide and narrow items request a 3:1 share of the available width. It shows the label, draws an outer border, and supplies a plain linear fallback. The code constructs a block without sending a message; add it to your message's blocks and include API: Healthy in the message's top-level text.

Output

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

Service status
API
Healthy
Linear fallback
API: Healthy
Serialized output
{
"type": "layout",
"block_id": "service-layout",
"label": "Service status",
"is_label_visible": true,
"grid_lines": "outer",
"rows": [
{
"items": [
{
"block": {
"type": "section",
"block_id": "service",
"text": {
"type": "plain_text",
"text": "API"
}
},
"width": "wide"
},
{
"block": {
"type": "section",
"block_id": "status",
"text": {
"type": "plain_text",
"text": "Healthy"
}
},
"width": "narrow"
}
]
}
],
"fallback": [
{
"type": "section",
"block_id": "fallback",
"text": {
"type": "plain_text",
"text": "API: Healthy"
}
}
]
}
from slackblocks import LayoutBlock, LayoutRow, LayoutItem, PlainText, SectionBlock

layout = LayoutBlock(
label="Service status", block_id="service-layout", is_label_visible=True,
grid_lines="outer",
rows=[LayoutRow(items=[
LayoutItem(block=SectionBlock(text=PlainText("API"), block_id="service"), width="wide"),
LayoutItem(block=SectionBlock(text=PlainText("Healthy"), block_id="status"), width="narrow"),
])],
fallback=[SectionBlock(text=PlainText("API: Healthy"), block_id="fallback")],
)
print(layout)

To extend this to several rows with aligned status text, see the weighted layout recipe.

Labels, widths and alignment​

The required label is 1–150 Unicode code points. It is hidden unless is_label_visible is true; visible labels are bold text rather than headings, and hidden labels are not accessible names.

Widths are narrow (1), standard (2, the default) and wide (3). Explicit alignment is start, center or end; omission fills the cell. grid_lines accepts none, rows (outer plus horizontal dividers) or outer.

Supported children and surfaces​

PlacementSupported content
Layout itemActions, alert, card, carousel, container, context, data table, data visualization, divider, file, header, image, input, rich text, section, table, video
FallbackContext, divider, header, image, rich text, section, table, video
Receiving surfacesMessages, modals and App Home, subject to each child's own surface restrictions

Direct nested layouts and markdown blocks are not layout children. A layout/container path allows at most two composite levels. A container may contain a layout where that container is supported; existing container-only nesting behavior is unchanged.

A row may contain only one carousel, data table or chart; a chart must receive more than half the row's total weight. A wide chart beside a standard item is valid; equal weights are not. In a three-item row, a wide chart beside two narrow items also has a strict majority (3 of 5); three omitted widths do not (2 of 6). The rule is independent of the chart's position.

Fallback and validation​

Fallback replaces the grid on clients without layout support. Explicit empty fallback remains empty. Child and fallback blocks must be valid on the receiving surface; for example, nesting an input in a modal still requires a submit label. Existing aggregate chart and text limits continue to apply. Layout accounting explains the retained top-level block limits and the observed Slack discrepancy.

Official Slack layout reference.