Skip to main content

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​

FieldTypeDescriptionRequired?
typeStringThe type of block. For a layout block, type is always layout.Required
labelStringDescribes 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
rowsArrayArray of layout row objects. Minimum 1, maximum 5.Required
is_label_visibleBooleanWhen set to true, renders the label as bold text above the grid. Defaults to false.Optional
grid_linesStringOne of none (default), rows, or outer. Refer to how items share space.Optional
fallbackArrayStable 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_idStringA 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.

FieldTypeDescriptionRequired?
itemsArrayCan be from 1–3 layout item objects, rendered horizontally in order.Required

Layout item fields​

FieldTypeDescriptionRequired?
blockObjectThe 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
widthStringOne of narrow, standard (default), or wide. Refer to how items share space.Optional
horizontal_alignmentStringOne 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 settingRelative weightBehavior
narrow1Smallest share of the row
standard (default)2Default share
wide3Largest 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 settingBehavior
startContent aligned to the leading edge
centerContent centered
endContent 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 settingBehavior
none (default)No border and no dividers; blocks float in the surface
rowsAn outer border plus a horizontal divider between each pair of rows
outerAn 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:

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_text or use a section block with mrkdwn text.

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 label field name is not an accessible name. When is_label_visible is set to false, the label isn't rendered at all and is not exposed to screen readers. Setting it to true renders 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 a header block above the layout block.
  • Don't use layout for 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 the layout block, 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 the update your app to see this message notice, so the message still reads cleanly rather than showing an unsupported-block warning.

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"
}
]
}
}
]
}
]
}
]
}

View in Block Kit Builder