Layout block
The layout block arranges other blocks into a grid of rows and side-by-side items so that a single message or view can present structured, multi-column content rather than one vertical stack.
Fields
Top-level fields
| Field | Type | Description | Required? |
|---|---|---|---|
type | String | The type of block. For a layout block, type is always layout. | Required |
label | String | Describes the layout block. Maximum 150 characters. Shown above the grid only when is_label_visible is true, and carries no heading semantics. A layout block's contribution to the enclosing surface's block and character limits includes its label plus every nested child block, so a dense layout consumes proportionally more of the surface budget. Refer to accessibility considerations. | Required |
rows | Array | Array of layout row objects. Minimum 1, maximum 5. | Required |
is_label_visible | Boolean | When set to true, renders the label as bold text above the grid. Defaults to false. | Optional |
grid_lines | String | One of none (default), rows, or outer. Refer to how items share space. | Optional |
fallback | Array | Stable top-level blocks rendered by clients that don't support layout blocks. Optional on input; always present on output, as an empty array when you supply none. | Optional |
block_id | String | A unique identifier for a block. If not specified, a block_id will be generated. | Optional |
Layout row field
A row has no other properties. Row-level alignment is not supported; alignment is set per item.
| Field | Type | Description | Required? |
|---|---|---|---|
items | Array | Can be from 1–3 layout item objects, rendered horizontally in order. | Required |
Layout item fields
| Field | Type | Description | Required? |
|---|---|---|---|
block | Object | The child block rendered in this layout item. Must be an allowed child block type. Therefore, the number of child blocks per layout block allowed is 15 (5 layout rows × 3 layout items). | Required |
width | String | One of narrow, standard (default), or wide. Refer to how items share space. | Optional |
horizontal_alignment | String | One of start, center, or end. Omit for default fill behavior. | Optional |
How items share row space
The width field
The width field is a proportional hint, not a fixed fraction. The following values weight an item's share of the row:
width setting | Relative weight | Behavior |
|---|---|---|
narrow | 1 | Smallest share of the row |
standard (default) | 2 | Default share |
wide | 3 | Largest share |
Each item's share depends on the other items in the same row, and those weights are the ratio. A narrow item next to a wide item splits the row 1:3, so it takes roughly a quarter to the wide item's three quarters. Three standard items split the row into thirds. Keep in mind that for mobile views, row items will always stack.
Each width also carries a minimum size: when a row can't fit its items above their minimums, such as a narrow desktop pane or any mobile viewport, items wrap to the following line in source order. Nothing is hidden, truncated, or reordered.
The horizontal_alignment field
The horizontal_alignment field positions the item's content within its own cell:
horizontal_alignment setting | Behavior |
|---|---|
start | Content aligned to the leading edge |
center | Content centered |
end | Content aligned to the trailing edge |
Omit horizontal_alignment to get the default fill behavior, where content spans the cell's width. Alignment is direction-aware: start and end follow the reader's text direction rather than always meaning left and right.
The grid_lines field
The grid_lines field controls the borders drawn around and between rows:
grid_lines setting | Behavior |
|---|---|
none (default) | No border and no dividers; blocks float in the surface |
rows | An outer border plus a horizontal divider between each pair of rows |
outer | An outer border only, with no internal dividers |
There are no vertical dividers between items.
Allowed child block types
An layout item's block field must one of the following:
- actions
- alert
- card
- carousel
- container
- context
- data_table
- data_visualization
- divider
- file
- header
- image
- input
- rich_text
- section
- table
- video
In addition to this list, the following constraints apply:
- The child must be valid on the surface where the layout block appears. Children go through the same container gating as top-level blocks, so a child type that isn't allowed in Messages for example is rejected inside a layout on that surface as well, with the error
Block type is not supported in this container. - A layout block can nest a container block, and a container block can nest a layout block. This cycle is limited to 2 levels of recursion, i.e., layout > container > rich_text is valid, but layout > container > layout > rich_text is invalid.
- The carousel, data table, and data visualization blocks take up more real estate, and cannot appear in a row with one another. The data visualization block is particularly wide, and must be allocated more than half of the row space.
- Markdown blocks are invalid. If needed, convert any markdown and send
rich_textor use a section block withmrkdwntext.
Accessibility considerations
This block is purely visual. It adds no grid, table, or group semantics, which keeps it out of the way of assistive technology, but also means that it carries none of the affordances tabular content requires.
- Reading order matches visual order. Items are emitted row by row, in source order. Wrapping on narrow viewports preserves that order.
- Keyboard behavior is unchanged. The layout block isn't focusable and adds no key handling; tab order follows the interactive elements of your child blocks in source order.
- The
labelfield name is not an accessible name. Whenis_label_visibleis set tofalse, the label isn't rendered at all and is not exposed to screen readers. Setting it totruerenders the label as bold text that is read in reading order; it is styled like a heading but carries no heading semantics, so it is not announced as one and does not label the grid as a group. If the grouping needs to be announced, put aheaderblock above the layout block. - Don't use
layoutfor tabular data. It has no column headers, caption, or cell relationships. Use the table block, which provides real grid semantics.
Because reading order follows source order, put items in the order you want them read, not the order that happens to look right once wrapped.
Fallback behavior
Clients that don't recognize layout blocks replace the block with the contents of your fallback array:
- If you supply
fallback, those blocks render in place of thelayoutblock, spliced into the parent blocks array. - If you omit
fallback, Slack sets it to an empty array. Nothing renders in place of the layout block , but the empty array also suppresses theupdate your app to see this messagenotice, so the message still reads cleanly rather than showing anunsupported-blockwarning.
Slack does not synthesize fallback content from your rows. An omitted fallback means clients that don't support layout blocks see none of the content, so supply fallback whenever the layout carries information the message can't do without. For example:
{
"type": "layout",
"label": "Deal summary for Borant Corp",
"rows": ["..."],
"fallback": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Deal summary for Borant Corp*\nStage: Negotiation · Amount: $125,000 · Close: 2026-10-15"
}
}
]
}
The fallback field accepts stable top-level blocks only; the block types every supported client is committed to render. That set is exactly the following blocks:
Any other block type is rejected with an invalid_block error.
Full example
A sales agent summarizes a deal with structured side-by-side layout. This example demonstrates the width and horizontal_alignment fields on a layout item wrapping an actions block, and button style variants (primary, danger):
{
"blocks": [
{
"type": "layout",
"block_id": "deal_summary_layout",
"label": "Deal summary for Borant Corp",
"is_label_visible": true,
"rows": [
{
"items": [
{
"block": {
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Stage*\nNegotiation"
}
}
},
{
"block": {
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Amount*\n$125,000"
}
}
},
{
"block": {
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Close*\n2026-08-15"
}
}
}
]
},
{
"items": [
{
"block": {
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Next Steps*\nSchedule sponsor meeting and finalize agreement"
}
}
}
]
},
{
"items": [
{
"width": "narrow",
"horizontal_alignment": "end",
"block": {
"type": "actions",
"elements": [
{
"type": "button",
"text": {
"type": "plain_text",
"text": "View in Salesforce"
},
"style": "primary"
},
{
"type": "button",
"text": {
"type": "plain_text",
"text": "Update Stage"
},
"style": "danger"
}
]
}
}
]
}
]
}
]
}