Guide
Using ButtonKit

Using ButtonKit

ButtonKit is an enhanced version of the native Discord.js ButtonBuilder (opens in a new tab), designed to simplify the process of creating and handling button interactions in your Discord bot.

It is not recommended to use this to listen for button clicks forever since it creates collectors. For that purpose, it's recommended to use a regular "interactionCreate" event listener.

Handle button clicks

commands/counter.js
const { ButtonKit } = require('commandkit');
const { ButtonStyle, ActionRowBuilder } = require('discord.js');
 
// Create a button
const button = new ButtonKit()
    .setEmoji('👍')
    .setStyle(ButtonStyle.Primary)
    .setCustomId('button'); // Required to use onClick
 
const buttonRow = new ActionRowBuilder().addComponents(button);
 
const message = await channel.send({ components: [buttonRow] });
 
// Listen to the button interaction right away
button.onClick(
    (interaction) => {
        // Reply to the interaction
        interaction.reply('You clicked the button!');
    },
    { message },
);

In the above example, you may notice how similar ButtonKit is to the native Discord.js ButtonBuilder class. That's because it's built on top of it. It introduces a new method called onClick which will allow you to quickly handle button interactions without having to create collectors. CommandKit does that for you!

⚠️

ButtonKit doesn't work without a custom ID, so ensure you provide one whenever instantiating a button. This is required to keep track of what button was clicked.

Arguments Explained

Here's an empty onClick method without any arguments:

const myButton = new ButtonKit()
  .setCustomId('custom_button')
  .setLabel('Click me!')
  .setStyle(ButtonStyle.Primary);
 
myButton.onClick();

The first argument required by this function is your handler function which will acknowledge button clicks (interactions) handled by ButtonKit. You can handle them like so:

myButton.onClick((buttonInteraction) => {
  buttonInteraction.reply('You clicked a button!');
});

However, the code above won't actually work since ButtonKit doesn't have any idea where it's supposed to specifically listen button clicks from. To fix that, you need to pass in a second argument, also known as your options which houses all the collector configuration. The message property is the message that ButtonKit will use to listen for button clicks.

const row = new ActionRowBuilder().addComponents(myButton);
const message = await channel.send({ components: [row] });
 
myButton.onClick(
  (buttonInteraction) => {
    buttonInteraction.reply('You clicked a button!');
  },
  { message },
);

This also works with interaction replies. Just ensure you pass fetchReply alongside your components:

const row = new ActionRowBuilder().addComponents(myButton);
const message = await interaction.reply({
  components: [row],
  fetchReply: true,
});
 
myButton.onClick(
  (buttonInteraction) => {
    buttonInteraction.reply('You clicked a button!');
  },
  { message },
);

ButtonKit onClick options

message

The message object that ButtonKit uses to listen for button clicks (interactions).

time (optional)

  • Type: number
  • Default: 86400000

The duration (in ms) the collector should run for and listen for button clicks.

autoReset (optional)

  • Type: boolean

Whether or not the collector should automatically reset the timer when a button is clicked.

Additional optional options

Handle collector end

When setting up an onClick() method using ButtonKit, you may also want to run some code after the collector ends running. The default timeout is 1 day, but you can modify this in onClickOptions#time. To handle when the collector ends, you can setup an onEnd() method like this:

const myButton = new ButtonKit()
  .setCustomId('custom_button')
  .setLabel('Click me!')
  .setStyle(ButtonStyle.Primary);
 
const row = new ActionRowBuilder().addComponents(myButton);
const message = await interaction.reply({
  components: [row],
  fetchReply: true,
});
 
myButton
  .onClick(
    (buttonInteraction) => {
      buttonInteraction.reply('You clicked a button!');
    },
    { message },
  )
  .onEnd(() => {
    console.log('Button collector ended.');
 
    myButton.setDisabled(true);
    message.edit({ components: [row] });
  });

Dispose button collector

⚠️

This feature is currently only available in the development version.

To dispose the button collector, you can make use of the dispose method. By disposing the collector like this, your onEnd handler (if any) will be called automatically.

myButton
  .onClick(
    (buttonInteraction) => {
      buttonInteraction.reply('You clicked a button!');
    },
    { message },
  )
  .onEnd(() => {
    console.log('Button collector ended.');
 
    myButton.setDisabled(true);
    message.edit({ components: [row] });
  });
 
myButton.dispose();