renderComponents
Translate the bot-ui BotNode IR to Discord Components V2, degrading within Discord's per-element budgets (DISCORD_LIMITS).
Overview
renderComponents translates the BotNode IR into a single top-level Components V2 ContainerBuilder; renderDiscordMessage additionally wraps it in the { components, flags } shape required by channel.send / message.edit, with MessageFlags.IsComponentsV2 set. The adapter calls these for you on every thread.post — reach for them directly when testing components or building custom egress.
Signature
import { renderComponents, renderDiscordMessage, DISCORD_LIMITS } from "@copilotkit/bot-discord";
function renderComponents(ir: BotNode[]): ContainerBuilder;
function renderDiscordMessage(ir: BotNode[]): {
components: ContainerBuilder[];
flags: number; // MessageFlags.IsComponentsV2
};Component mapping
| Component | Components V2 |
|---|---|
Message | outer ContainerBuilder (accent color if <Message accent="#hex">) |
Header | TextDisplayBuilder with # prefix |
Section / Markdown / Text | TextDisplayBuilder (Markdown rendered via discordMarkdown) |
Fields | TextDisplayBuilder with bold-label lines (**label** value) |
Context | TextDisplayBuilder with -# subtext lines |
Actions | one or more ActionRowBuilder (buttons chunked ≤5/row, selects each get their own row) |
Button | ButtonBuilder inside an ActionRowBuilder |
Select | StringSelectMenuBuilder inside its own ActionRowBuilder |
Image | MediaGalleryBuilder with one MediaGalleryItemBuilder |
Divider | SeparatorBuilder (small spacing, divider line) |
Table | TextDisplayBuilder with a reconstructed GFM pipe table fenced by discordMarkdown |
Input | skipped — modal-only on Discord; a warning is logged |
IsComponentsV2 flag
renderDiscordMessage always sets MessageFlags.IsComponentsV2 on the returned flags. Discord requires this flag when the message body contains a top-level ContainerBuilder; without it the API rejects the payload.
Per-element budgets
Discord caps every element. The renderer degrades instead of failing: over-long text is truncated with an overflow marker (…), and sub-collections (select options, action rows, buttons per row) are clamped to their caps. Nothing ever exceeds a platform limit. The limits ship as DISCORD_LIMITS (see DISCORD_LIMITS).
Related
- discord() — the adapter that calls this on every post
- BotNode — the IR this consumes
- renderToIR — producing the IR from JSX
- DISCORD_LIMITS — the per-element budget table