Using message components
Add components to a message with the components field: a list of action rows, each holding buttons or one menu.
A message with two rowsJSON
json
{
"content": "Pick a game night",
"components": [
{
"type": 1,
"components": [
{ "type": 2, "style": 3, "label": "Friday", "custom_id": "night:fri" },
{ "type": 2, "style": 2, "label": "Saturday", "custom_id": "night:sat" },
{ "type": 2, "style": 5, "label": "Rules", "url": "https://example.com/rules" }
]
},
{
"type": 1,
"components": [
{
"type": 3, "custom_id": "game", "placeholder": "Which game?", "min_values": 1, "max_values": 2,
"options": [
{ "label": "Hades", "value": "hades", "description": "Roguelike" },
{ "label": "Celeste", "value": "celeste" }
]
}
]
}
]
}Buttons
| Style | Value | Needs | Looks |
|---|---|---|---|
| Primary | 1 | custom_id | The accent colour |
| Secondary | 2 | custom_id | Grey |
| Success | 3 | custom_id | Green |
| Danger | 4 | custom_id | Red |
| Link | 5 | url | Grey, with an arrow. Opens the address; sends no interaction |
A button needs a label (up to 80 characters) or an emoji ({ "name": "🎲" }). Set disabled: true to grey it out. A link button's address must be https.
When a member presses a button you get:
What your endpoint receives (shortened)JSON
json
{
"type": 3,
"data": { "custom_id": "night:fri", "component_type": 2 },
"message": { "id": "…", "content": "Pick a game night" }
}Select menus
| Menu | Type | The member chooses from |
|---|---|---|
| String | 3 | Up to 25 options you define: { label, value, description?, emoji?, default? } |
| User | 5 | Members of the server |
| Role | 6 | Roles of the server |
| Mentionable | 7 | Members and roles |
| Channel | 8 | Channels of the server. channel_types narrows the list |
Common fields: custom_id, placeholder (up to 150 characters), min_values (0 to 25, default 1), max_values (1 to 25, default 1), disabled. User, role, mentionable and channel menus can have default_values: [ { id, type: "user" | "role" | "channel" } ].
You get data.values: for a string menu the values of the options chosen; for the others the ids chosen, with data.resolved saying what they are. Moymo has already checked that the number chosen is within min_values and max_values, that string values are among your options, and that ids exist in the server.
Answering a press
- Change the message (
type 7):{ "type": 7, "data": { "content": "Friday it is!", "components": [] } }. Fields you leave out stay. - Write a new message (
type 4), often withflags: 64so only the member sees it. - Open a form (
type 9). - Acknowledge (
type 6) and edit the message later.
A counter, end to end
The two answers of a counter
js
return {
type: 4,
data: {
content: 'Count: 0',
components: [{
type: 1,
components: [{ type: 2, style: 1, label: '+1', custom_id: 'plus' }]
}]
}
}js
// the message arrives in interaction.message
const count = Number(interaction.message.content.split(': ')[1]) + 1
return { type: 7, data: { content: `Count: ${count}` } }Things to remember
- Components are on the message, and last as long as it does. Keep what you need to continue in the
custom_idor in your own storage. - Anybody who can send messages in the channel can press its buttons. Check
interaction.memberand itspermissionsbefore you do anything that should be restricted. - Edit a message and its components are replaced as you say;
components: []removes them all. - A bot's own messages are always readable by the bot, so
interaction.messagehas the content even without the message content intent.