Skip to main content
Version: Next

SelectMenuKit

SelectMenuKit consists of several enhanced versions of Discord.js select menu builders:

  • StringSelectMenuKit - For text-based selection
  • UserSelectMenuKit - For selecting Discord users
  • RoleSelectMenuKit - For selecting Discord roles
  • ChannelSelectMenuKit - For selecting Discord channels
  • MentionableSelectMenuKit - For selecting mentionable Discord entities

Each extends its respective Discord.js counterpart while adding methods like onSelect() to handle selections without manually setting up collectors.

info

CommandKit provides JSX version of SelectMenuKit as an alternative syntax to the standard Discord.js builders. This is not required, but can be useful for those who prefer a more declarative style. See <SelectMenu/> for more details.

Basic Usage

String Select Menu

const { StringSelectMenuKit } = require('commandkit');
const { StringSelectMenuOptionBuilder, ActionRowBuilder } = require('discord.js');

// Create and configure a select menu
const select = new StringSelectMenuKit()
.setCustomId('pokemon-select')
.setPlaceholder('Choose a starter Pokémon')
.addOptions(
new StringSelectMenuOptionBuilder()
.setLabel('Bulbasaur')
.setDescription('The dual-type Grass/Poison Seed Pokémon.')
.setValue('bulbasaur'),
new StringSelectMenuOptionBuilder()
.setLabel('Charmander')
.setDescription('The Fire-type Lizard Pokémon.')
.setValue('charmander'),
new StringSelectMenuOptionBuilder()
.setLabel('Squirtle')
.setDescription('The Water-type Tiny Turtle Pokémon.')
.setValue('squirtle')
);

// Add select menu to a row
const row = new ActionRowBuilder().addComponents(select);

// Send message with select menu
await interaction.reply({
content: 'Choose your starter Pokémon:',
components: [row],
});

// Handle selections
select.onSelect((interaction) => {
const selected = interaction.values[0];
interaction.reply(`You chose ${selected}!`);
});

User Select Menu

const { UserSelectMenuKit } = require('commandkit');
const { ActionRowBuilder } = require('discord.js');

// Create a user select menu
const userSelect = new UserSelectMenuKit()
.setCustomId('user-select')
.setPlaceholder('Select users')
.setMinValues(1)
.setMaxValues(3);

const row = new ActionRowBuilder().addComponents(userSelect);

await interaction.reply({
content: 'Select up to 3 users:',
components: [row],
});

userSelect.onSelect((interaction) => {
const users = interaction.users.map(user => user.username).join(', ');
interaction.reply(`You selected: ${users}`);
});
Important

Always set a customId when using any SelectMenuKit. This is required to track select menu interactions.

Other Select Menu Types

Role Select Menu

import { RoleSelectMenuKit } from 'commandkit';

const roleSelect = new RoleSelectMenuKit()
.setCustomId('role-select')
.setPlaceholder('Select roles')
.setMinValues(1)
.setMaxValues(3);

// Handle selections
roleSelect.onSelect((interaction) => {
const roles = interaction.roles.map((role) => role.name).join(', ');
interaction.reply(`You selected these roles: ${roles}`);
});

Channel Select Menu

import { ChannelSelectMenuKit } from 'commandkit';

const channelSelect = new ChannelSelectMenuKit()
.setCustomId('channel-select')
.setPlaceholder('Select channels');

channelSelect.onSelect((interaction) => {
const channels = interaction.channels
.map((channel) => channel.name)
.join(', ');
interaction.reply(`You selected these channels: ${channels}`);
});

Mentionable Select Menu

import { MentionableSelectMenuKit } from 'commandkit';

const mentionableSelect = new MentionableSelectMenuKit()
.setCustomId('mentionable-select')
.setPlaceholder('Select users or roles');

mentionableSelect.onSelect((interaction) => {
const mentions = [
...interaction.users.map((user) => user.username),
...interaction.roles.map((role) => role.name),
].join(', ');

interaction.reply(`You selected: ${mentions}`);
});

Configuration Options

The onSelect method accepts two parameters:

  1. A handler function that receives the select menu interaction
  2. An options object to configure the collector

Handler Function

(interaction: SelectMenuInteraction) => void | Promise<void>

Collector Options

interface SelectMenuKitOptions {
time?: number; // Duration in ms (default: 5 * 60 * 1000 - 5 minutes)
autoReset?: boolean; // Reset timer on selection (default: false)
once?: boolean; // Listen for single selection only (default: true)
// Plus all Discord.js InteractionCollectorOptions
}

Example with options:

selectMenu.onSelect(
(interaction) => {
interaction.reply(`You selected ${interaction.values.join(', ')}!`);
},
{
time: 120000, // 2 minutes
autoReset: true, // Reset timer on each selection
once: false, // Handle multiple selections
},
);

Additional Methods

Filtering Interactions

Use filter() to only process selections that meet specific criteria:

selectMenu
.filter((interaction) => interaction.user.id === '123456789012345678')
.onSelect((interaction) => {
interaction.reply('Only a specific user can use this menu!');
});

Handling Collector End

Use onEnd() to run code when the collector stops:

selectMenu
.onSelect((interaction) => {
interaction.reply('Selection received!');
})
.onEnd(() => {
// Disable the menu
selectMenu.setDisabled(true);
message.edit({ components: [row] });
});

Error Handling

Use onError() to handle any errors that occur during the interaction:

selectMenu
.onSelect((interaction) => {
interaction.reply('Selection received!');
})
.onError((error) => {
console.error('An error occurred:', error);
});

Manually Stopping the Collector

Use dispose() to manually stop the collector. This will trigger the onEnd handler if one exists.

// Stop listening for selections
selectMenu.dispose();