---
title: "renderBlockKit"
description: "Translate the bot-ui BotNode IR to Slack Block Kit, degrading within Slack's per-element budgets (SLACK_LIMITS)."
---

## Overview

`renderBlockKit` translates the [BotNode IR](/reference/bot/types/BotNode) into Block Kit blocks; `renderSlackMessage` additionally extracts a top-level `<Message accent>` into the accent color for an attachment. The adapter calls these for you on every [`thread.post`](/reference/bot/classes/Thread) — reach for them directly when testing components or building custom egress.

## Signature

```ts
import { renderBlockKit, renderSlackMessage, SLACK_LIMITS } from "@copilotkit/bot-slack";

function renderBlockKit(ir: BotNode[]): KnownBlock[];

function renderSlackMessage(ir: BotNode[]): {
  blocks: KnownBlock[];
  accent?: string;
};
```

## Component mapping

| Component | Block Kit |
|-----------|-----------|
| [`Message`](/reference/bot/components/Message) | the message's `blocks` (or an accent attachment) |
| [`Header`](/reference/bot/components/Header) | `header` |
| [`Section`](/reference/bot/components/Section) / [`Markdown`](/reference/bot/components/Markdown) | `section` (mrkdwn) |
| [`Fields`](/reference/bot/components/Fields) | `section.fields` |
| [`Context`](/reference/bot/components/Context) | `context` |
| [`Actions`](/reference/bot/components/Actions) | `actions` |
| [`Button`](/reference/bot/components/Button) | `button` (`action_id` = minted opaque id) |
| [`Select`](/reference/bot/components/Select) | `static_select` |
| [`Input`](/reference/bot/components/Input) | `plain_text_input` |
| [`Image`](/reference/bot/components/Image) | `image` |
| [`Divider`](/reference/bot/components/Divider) | `divider` |
| [`Table`](/reference/bot/components/Table) | native `table` block |

## Per-element budgets

Slack caps every element. The renderer **degrades instead of failing**: over-long text is truncated with an overflow marker, and the top-level block list is clamped to 50 with an overflow-signal context block appended when blocks had to be dropped. Sub-collections (fields, actions elements, context elements, select options, table rows/columns) are clamped to their caps **without** a marker — an 11th field or 26th button is dropped silently. Nothing ever exceeds a platform limit. The limits ship as `SLACK_LIMITS`:

| Limit | Value | Element |
|-------|-------|---------|
| `blocksPerMessage` | 50 | blocks per message |
| `sectionText` | 3000 | section body chars |
| `headerText` | 150 | header chars |
| `fieldsPerSection` | 10 | fields per section |
| `fieldText` | 2000 | field chars |
| `actionsElements` | 25 | controls per actions row |
| `contextElements` | 10 | elements per context block |
| `buttonText` | 75 | button label chars |
| `actionId` | 255 | `action_id` chars |
| `buttonValue` | 2000 | button value chars |
| `selectOptions` | 100 | options per select |
| `tableColumns` | 20 | columns per table |
| `tableRows` | 100 | rows per table |
| `cellText` | 2000 | table cell chars |

## Accent attachments

Block Kit has no native accent color, so a single top-level `<Message accent="#27AE60">` is surfaced by `renderSlackMessage` as `accent`, and the adapter posts the blocks as an attachment with a colored left bar: `attachments: [{ color, blocks }]`.

## Related

- [slack()](/reference/bot/slack) — the adapter that calls this on every post
- [BotNode](/reference/bot/types/BotNode) — the IR this consumes
- [renderToIR](/reference/bot/functions/renderToIR) — producing the IR from JSX
