Buttons

With the components API, you can create interactive message components. On this page, we'll cover how to send, receive, and respond to buttons using discord.js!

TIP

This page is a follow-up to the interactions (slash commands) pages. Please carefully read those first so that you can understand the methods used in this section.

Building and sending buttons

Buttons are part of the MessageComponent class, which can be sent via messages or interaction responses. A button, as any other message component, must be in an ActionRow.

WARNING

You can have a maximum of five ActionRows per message, and five buttons within an ActionRow.

To create a button, use the MessageActionRow() and MessageButton() builder functions and then pass the resulting object to CommandInteraction#reply() as InteractionReplyOptions:

const { MessageActionRow, MessageButton } = require('discord.js');

client.on('interactionCreate', async interaction => {
	if (!interaction.isCommand()) return;

	if (interaction.commandName === 'ping') {
		const row = new MessageActionRow()
			.addComponents(
				new MessageButton()
					.setCustomId('primary')
					.setLabel('Primary')
					.setStyle('PRIMARY'),
			);

		await interaction.reply({ content: 'Pong!', components: [row] });
	}
});
 





 
 
 
 
 
 
 

 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

TIP

The custom ID is a developer-defined string of up to 100 characters.

Restart your bot and then send the command to a channel your bot has access to. If all goes well, you should see something like this:

User used /ping
Guide Bot07/12/2021
Pong!

You can also send message components within an ephemeral response or alongside message embeds.

const { MessageActionRow, MessageButton, MessageEmbed } = require('discord.js');

client.on('interactionCreate', async interaction => {
	if (!interaction.isCommand()) return;

	if (interaction.commandName === 'ping') {
		const row = new MessageActionRow()
			.addComponents(
				// ...
			);

		const embed = new MessageEmbed()
			.setColor('#0099ff')
			.setTitle('Some title')
			.setURL('https://discord.js.org/')
			.setDescription('Some description here');

		await interaction.reply({ content: 'Pong!', ephemeral: true, embeds: [embed], components: [row] });
	}
});
 










 
 
 
 
 

 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
User used /ping
Guide Bot07/12/2021
Pong!
Some description here
Only you can see this

Disabled buttons

If you want to prevent a button from being used, but not remove it from the message, you can disable it with the setDisabled() method:

const button = new MessageButton()
	.setCustomId('primary')
	.setLabel('Primary')
	.setStyle('PRIMARY')
	.setDisabled(true);




 
1
2
3
4
5
User used /ping
Guide Bot07/12/2021
Pong!

Emoji buttons

If you want to use a guild emoji within a MessageButton, you can use the setEmoji() method:

const button = new MessageButton()
	.setCustomId('primary')
	.setLabel('Primary')
	.setStyle('PRIMARY')
	.setEmoji('123456789012345678');




 
1
2
3
4
5

Now you know all there is to building and sending a MessageButton! Let's move on to receiving button interactions!

Receiving buttons

To receive a ButtonInteraction, attach an event listener to your client and use the Interaction#isButton() type guard to make sure you only receive buttons:

client.on('interactionCreate', interaction => {
	if (!interaction.isButton()) return;
	console.log(interaction);
});

 


1
2
3
4

Component collectors

These work quite similarly to message and reaction collectors, except that you will receive instances of the MessageComponentInteraction class as collected items.

TIP

You can create the collectors on either a message or a channel.

For a detailed guide on receiving message components via collectors, please refer to the collectors guide.

Responding to buttons

The MessageComponentInteraction class provides the same methods as the CommandInteraction class. These methods behave equally:

  • reply()
  • editReply()
  • defer()
  • fetchReply()
  • deleteReply()
  • followUp()

Updating the button message

The MessageComponentInteraction class provides an update() method to update the message the button is attached to. Passing an empty array to the components option will remove any buttons after one has been clicked.

const filter = i => i.customId === 'primary' && i.user.id === '122157285790187530';

const collector = interaction.channel.createMessageComponentCollector({ filter, time: 15000 });

collector.on('collect', async i => {
	if (i.customId === 'primary') {
		await i.update({ content: 'A button was clicked!', components: [] });
	}
});

collector.on('end', collected => console.log(`Collected ${collected.size} items`));





 
 
 



1
2
3
4
5
6
7
8
9
10
11

Deferring and updating the button message

In addition to deferring an interaction response, you can defer the button, which will trigger a loading state and then revert to its original state:

const wait = require('util').promisify(setTimeout);

// ...

collector.on('collect', async i => {
	if (i.customId === 'primary') {
		await i.deferUpdate();
		await wait(4000);
		await i.editReply({ content: 'A button was clicked!', components: [] });
	}
});

collector.on('end', collected => console.log(`Collected ${collected.size} items`));






 
 
 




1
2
3
4
5
6
7
8
9
10
11
12
13

Button styles

Currently there are five different button styles available:

  • PRIMARY, a blurple button;
  • SECONDARY, a grey button;
  • SUCCESS, a green button;
  • DANGER, a red button;
  • LINK, a button that navigates to a URL.
Guide Bot07/12/2021
Link

WARNING

Only LINK buttons can have a url. LINK buttons cannot have a custom_id and do not send an interaction event when clicked.