Skip to content

Components — buttons, selects, modals

Status Stable · Last verified 2026-07-11 · API v10 · Source Component reference

Components are the interactive and layout building blocks of a message: buttons, select menus, modals, and (with Components V2) text/containers/media too.

  • Classic components — buttons and select menus placed in action rows, sent alongside content/embeds. No special flag.
  • Components V2 — opt in per message with the IS_COMPONENTS_V2 flag (1 << 15 = 32768) to compose the entire message from components. See below.

Use classic components unless you specifically want V2’s layout richness.

Component Type Group
Action Row 1 Layout (holds other components)
Button 2 Interactive
String Select 3 Interactive
Text Input 4 Modal input
User Select 5 Interactive
Role Select 6 Interactive
Mentionable Select 7 Interactive
Channel Select 8 Interactive
Section 9 Components V2
Text Display 10 Components V2
Thumbnail 11 Components V2
Media Gallery 12 Components V2
File 13 Components V2
Separator 14 Components V2
Container 17 Components V2
Label 18 Form (wraps an input with label + description)
File Upload 19 Form input

[!TIP] Observation Additional newer form components (e.g. Radio Group 21, Checkbox Group 22, Checkbox 23) appear in the component reference. Treat the newest ones as fast-moving; confirm availability in the component reference before relying on them.

Style Value Required field
Primary 1 custom_id
Secondary 2 custom_id
Success 3 custom_id
Danger 4 custom_id
Link 5 url (no interaction fired)
Premium 6 sku_id (monetization upsell)
  • custom_id is developer-defined, returned to you on click. Length 1–100 characters.
  • Link buttons open a URL and send no interaction. Premium buttons point at a SKU.
  • Up to 5 buttons per action row.

Types 3 (string), 5 (user), 6 (role), 7 (mentionable), 8 (channel). A select menu must be alone in its action row (no buttons beside it). Configure min_values/max_values for multi-select; string selects define their own options.

Context Limit
Buttons per action row 5
Select menu per action row 1 (occupies the whole row)
Classic message up to 5 action rows
Components V2 message up to 40 total components

A modal is a pop-up form you open in response to an interaction (response type 9, MODAL). Modals collect input, then send you a MODAL_SUBMIT interaction (incoming type 5).

  • Text Input is component type 4, style Short (1, single-line) or Paragraph (2, multi-line); min_length/max_length range 0–4000.
  • Each input carries a custom_id (1–100 chars) you read on submit.
  • Modals have a title and a custom_id.

[!NOTE] Verified — wrap inputs in a Label component The official component reference states Discord “no longer recommend[s] using Text Input within an Action Row in modals. Going forward all Text Inputs should be placed inside a Label component” (type 18, carrying label + description). “Label is recommended for use over an Action Row in modals.”

[!TIP] Observation — per-modal numeric caps The official component reference does not pin a modal title length or a max-components-per-modal count. Commonly-cited figures (title ≤ 45; up to 5 top-level components; Label label ≤ 45, description ≤ 100) come from the discord.js guide, not the API reference — treat them as ecosystem guidance and confirm against a rejected payload rather than as official limits.

Set message flag IS_COMPONENTS_V2 (1 << 15) to build the message from components (Text Display 10, Container 17, Section 9, Media Gallery 12, Separator 14, …) instead of content/embeds.

[!CAUTION] Verified — irreversible, and mutually exclusive with content/embeds With IS_COMPONENTS_V2 set, content and embeds no longer work (use Text Display and Container instead), the message allows up to 40 total components, and once sent with the flag it cannot be removed from that message. Source: Component reference.

When a user clicks a button or uses a select, you receive a MESSAGE_COMPONENT interaction (type 3) carrying the component’s custom_id. Route on it:

if (interaction.type === 3) { // MESSAGE_COMPONENT
const id = interaction.data.custom_id; // e.g. "vote:yes"
// Respond with UPDATE_MESSAGE (7) to edit in place, or a new message (4),
// or DEFERRED_UPDATE_MESSAGE (6) if you need time. See responses & follow-ups.
}

Encode routing data into custom_id (e.g. "cart:remove:42"), but never trust it — see Security pitfalls.