String select menus (also called dropdowns) allow users to select one or more options from a predefined list of text choices.
String select menus in djs-core are created using the StringSelectMenu class. Each select menu component file in src/components/selects/string/ is automatically registered.
import { StringSelectMenu } from "@djs-core/runtime";
export default new StringSelectMenu()
.setPlaceholder("Choose a color")
.addOptions([
{ label: "Red", value: "red" },
{ label: "Blue", value: "blue" },
{ label: "Green", value: "green" },
])
.run(async (interaction) => {
const selectedColor = interaction.values[0];
await interaction.reply(`You selected: ${selectedColor}`);
});
You can add multiple options to a select menu (up to 25 options):
import { StringSelectMenu } from "@djs-core/runtime";
export default new StringSelectMenu()
.setPlaceholder("Select your language")
.addOptions([
{ label: "English", value: "en" },
{ label: "French", value: "fr" },
{ label: "Spanish", value: "es" },
{ label: "German", value: "de" },
{ label: "Italian", value: "it" },
])
.run(async (interaction) => {
const language = interaction.values[0];
await interaction.reply(`Language set to: ${language}`);
});
You can add emojis to options:
import { StringSelectMenu } from "@djs-core/runtime";
export default new StringSelectMenu()
.setPlaceholder("Choose your favorite food")
.addOptions([
{ label: "Pizza", value: "pizza", emoji: "🍕" },
{ label: "Burger", value: "burger", emoji: "🍔" },
{ label: "Sushi", value: "sushi", emoji: "🍣" },
{ label: "Taco", value: "taco", emoji: "🌮" },
])
.run(async (interaction) => {
const food = interaction.values[0];
await interaction.reply(`Great choice! ${food} is delicious!`);
});
String select menus can allow users to select multiple options:
import { StringSelectMenu } from "@djs-core/runtime";
export default new StringSelectMenu()
.setPlaceholder("Select your interests")
.setMinValues(1)
.setMaxValues(5)
.addOptions([
{ label: "Gaming", value: "gaming" },
{ label: "Music", value: "music" },
{ label: "Sports", value: "sports" },
{ label: "Movies", value: "movies" },
{ label: "Books", value: "books" },
])
.run(async (interaction) => {
const interests = interaction.values;
await interaction.reply(`You selected: ${interests.join(", ")}`);
});
setMinValues(n) - Minimum number of selections required (1-25)setMaxValues(n) - Maximum number of selections allowed (1-25)import { StringSelectMenu } from "@djs-core/runtime";
export default new StringSelectMenu()
.setPlaceholder("Select 2-4 tags")
.setMinValues(2)
.setMaxValues(4)
.addOptions([
{ label: "Tag 1", value: "tag1" },
{ label: "Tag 2", value: "tag2" },
{ label: "Tag 3", value: "tag3" },
{ label: "Tag 4", value: "tag4" },
{ label: "Tag 5", value: "tag5" },
])
.run(async (interaction) => {
const tags = interaction.values;
await interaction.reply(`Selected ${tags.length} tag(s): ${tags.join(", ")}`);
});
Select menus are typically sent as part of a command response:
import { Command, StringSelectMenu } from "@djs-core/runtime";
import { ActionRowBuilder } from "discord.js";
import colorSelect from "../../components/selects/string/color";
export default new Command()
.setDescription("Choose a color")
.run(async (interaction) => {
const row = new ActionRowBuilder<StringSelectMenu>().addComponents(
colorSelect,
);
await interaction.reply({
content: "Select a color from the menu below:",
components: [row],
});
});
Select menus can receive custom data. Important: The data is not set in the component definition, but when you use the select menu from a command or another component.
import { StringSelectMenu } from "@djs-core/runtime";
export default new StringSelectMenu<{ category: string }>()
.setPlaceholder("Select a product")
.run(async (interaction, data) => {
const product = interaction.values[0];
await interaction.reply(
`Selected ${product} from category: ${data.category}`,
);
});
When using the select menu from a command, set the data:
import { Command, StringSelectMenu } from "@djs-core/runtime";
import { ActionRowBuilder } from "discord.js";
import productSelect from "../../components/selects/string/product";
export default new Command()
.setDescription("Browse products")
.addStringOption((option) =>
option
.setName("category")
.setDescription("Product category")
.setRequired(true),
)
.run(async (interaction) => {
const category = interaction.options.getString("category");
// Set data and add options when using the select menu
const row = new ActionRowBuilder<StringSelectMenu>().addComponents(
productSelect
.setData({ category })
.addOptions([
{ label: "Laptop", value: "laptop" },
{ label: "Phone", value: "phone" },
{ label: "Tablet", value: "tablet" },
]),
);
await interaction.reply({
content: `Select a product from ${category}:`,
components: [row],
});
});
Select menus can be disabled:
import { StringSelectMenu } from "@djs-core/runtime";
export default new StringSelectMenu()
.setPlaceholder("This menu is disabled")
.setDisabled(true)
.addOptions([
{ label: "Option 1", value: "opt1" },
{ label: "Option 2", value: "opt2" },
])
.run(async (interaction) => {
// This won't be called when disabled
await interaction.reply("Menu is disabled");
});
Select menu responses can be ephemeral:
import { StringSelectMenu } from "@djs-core/runtime";
import { MessageFlags } from "discord.js";
export default new StringSelectMenu()
.setPlaceholder("Select an option")
.addOptions([
{ label: "Private Option 1", value: "opt1" },
{ label: "Private Option 2", value: "opt2" },
])
.run(async (interaction) => {
await interaction.reply({
content: "This response is only visible to you!",
flags: [MessageFlags.Ephemeral],
});
});
Select menus can be organized in subdirectories:
src/components/selects/string/
├── color.ts
├── language.ts
└── settings/
├── theme.ts
└── notification.ts