SelectMenuKit
SelectMenuKit consists of several enhanced versions of Discord.js select menu builders:
StringSelectMenuKit
- For text-based selectionUserSelectMenuKit
- For selecting Discord usersRoleSelectMenuKit
- For selecting Discord rolesChannelSelectMenuKit
- For selecting Discord channelsMentionableSelectMenuKit
- 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.
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
- CommonJS
- TypeScript
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}!`);
});
import { StringSelectMenuKit } from 'commandkit';
import {
StringSelectMenuOptionBuilder,
ActionRowBuilder,
type StringSelectMenuInteraction
} from 'discord.js';
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')
);
const row = new ActionRowBuilder<StringSelectMenuKit>().addComponents(select);
await interaction.reply({
content: 'Choose your starter Pokémon:',
components: [row],
});
select.onSelect((interaction: StringSelectMenuInteraction) => {
const selected = interaction.values[0];
interaction.reply(`You chose ${selected}!`);
});
User Select Menu
- CommonJS
- TypeScript
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}`);
});
import { UserSelectMenuKit } from 'commandkit';
import {
ActionRowBuilder,
type UserSelectMenuInteraction
} from 'discord.js';
const userSelect = new UserSelectMenuKit()
.setCustomId('user-select')
.setPlaceholder('Select users')
.setMinValues(1)
.setMaxValues(3);
const row = new ActionRowBuilder<UserSelectMenuKit>().addComponents(userSelect);
await interaction.reply({
content: 'Select up to 3 users:',
components: [row],
});
userSelect.onSelect((interaction: UserSelectMenuInteraction) => {
const users = interaction.users.map(user => user.username).join(', ');
interaction.reply(`You selected: ${users}`);
});
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:
- A handler function that receives the select menu interaction
- 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();