Components

Mentionable Select Menus

Learn how to create and use mentionable select menu components with djs-core.

Mentionable select menus allow users to select one or more Discord users or roles from the server. They combine the functionality of user and role select menus into a single component.

Mentionable select menus are flexible - users can select either users OR roles (or both) in a single menu. Perfect when you need flexibility in what can be selected.

Creating a Mentionable Select Menu

Mentionable select menus in djs-core are created using the MentionableSelectMenu class. Each select menu component file in src/components/selects/mentionable/ is automatically registered.

Use mentionable select menus when you want to let users choose either users or roles. For example, notification settings where users can select specific users or roles to mention, or permission systems that work with both users and roles.

Basic Mentionable Select Menu

import { MentionableSelectMenu } from "@djs-core/runtime";

export default new MentionableSelectMenu()
    .setPlaceholder("Select a user or role")
    .run(async (interaction) => {
        const selectedUser = interaction.users.first();
        const selectedRole = interaction.roles.first();
        
        if (selectedUser) {
            await interaction.reply(`You selected user: ${selectedUser.username}`);
        } else if (selectedRole) {
            await interaction.reply(`You selected role: ${selectedRole.name}`);
        }
    });

Multiple Selection

Mentionable select menus can allow users to select multiple users and/or roles:

import { MentionableSelectMenu } from "@djs-core/runtime";

export default new MentionableSelectMenu()
    .setPlaceholder("Select users or roles")
    .setMinValues(1)
    .setMaxValues(5)
    .run(async (interaction) => {
        const users = interaction.users.map((u) => u.username);
        const roles = interaction.roles.map((r) => r.name);
        
        let message = "";
        if (users.length > 0) {
            message += `Users: ${users.join(", ")}\n`;
        }
        if (roles.length > 0) {
            message += `Roles: ${roles.join(", ")}`;
        }
        
        await interaction.reply(message || "Nothing selected");
    });

Accessing Selected Items

You can access both users and roles from the interaction:

import { MentionableSelectMenu } from "@djs-core/runtime";

export default new MentionableSelectMenu()
    .setPlaceholder("Select users or roles to tag")
    .run(async (interaction) => {
        const userMentions = interaction.users.map((u) => u.toString()).join(" ");
        const roleMentions = interaction.roles.map((r) => r.toString()).join(" ");
        
        let message = "";
        if (userMentions) {
            message += `Users: ${userMentions}\n`;
        }
        if (roleMentions) {
            message += `Roles: ${roleMentions}`;
        }
        
        await interaction.reply(message || "Nothing selected");
    });

Distinguishing Between Users and Roles

You can check what type of mentionable was selected:

import { MentionableSelectMenu } from "@djs-core/runtime";

export default new MentionableSelectMenu()
    .setPlaceholder("Select a user or role")
    .run(async (interaction) => {
        const selectedUser = interaction.users.first();
        const selectedRole = interaction.roles.first();
        
        if (selectedUser) {
            await interaction.reply({
                content: `Selected a user: ${selectedUser.username} (${selectedUser.id})`,
            });
        } else if (selectedRole) {
            await interaction.reply({
                content: `Selected a role: ${selectedRole.name} (${selectedRole.id})`,
            });
        }
    });

Accessing Guild Members

For users selected in a server, you can also access guild member information:

import { MentionableSelectMenu } from "@djs-core/runtime";

export default new MentionableSelectMenu()
    .setPlaceholder("Select users or roles")
    .run(async (interaction) => {
        if (!interaction.inGuild()) {
            await interaction.reply("This menu only works in servers!");
            return;
        }
        
        let message = "";
        
        if (interaction.users.size > 0) {
            const members = interaction.members.map((m) => m.displayName);
            message += `Members: ${members.join(", ")}\n`;
        }
        
        if (interaction.roles.size > 0) {
            const roles = interaction.roles.map((r) => r.name);
            message += `Roles: ${roles.join(", ")}`;
        }
        
        await interaction.reply(message || "Nothing selected");
    });

Using Mentionable Select Menus in Commands

Mentionable select menus are typically sent as part of a command response:

import { Command, MentionableSelectMenu } from "@djs-core/runtime";
import { ActionRowBuilder } from "discord.js";
import mentionableSelect from "../../components/selects/mentionable/tag";

export default new Command()
    .setDescription("Tag users or roles")
    .run(async (interaction) => {
        const row = new ActionRowBuilder<MentionableSelectMenu>().addComponents(
            mentionableSelect,
        );
        
        await interaction.reply({
            content: "Select users or roles to tag:",
            components: [row],
        });
    });

Mentionable Select Menu Data

Mentionable select menus can receive custom data. Important: The data is set when you use the select menu from a command or another component, not in the component definition.

Component Definition (without data)

src/components/selects/mentionable/notify.ts
import { MentionableSelectMenu } from "@djs-core/runtime";

export default new MentionableSelectMenu<{ action: string }>()
    
    .setPlaceholder("Select users or roles to notify")
    .run(async (interaction, data) => {
        const users = interaction.users.map((u) => u.username);
        const roles = interaction.roles.map((r) => r.name);
        
        await interaction.reply(
            `Performing ${data.action} for users: ${users.join(", ") || "none"} and roles: ${roles.join(", ") || "none"}`,
        );
    });

Using Select Menu with Data

src/interactions/commands/notify.ts
import { Command, MentionableSelectMenu } from "@djs-core/runtime";
import { ActionRowBuilder } from "discord.js";
import notifySelect from "../../components/selects/mentionable/notify";

export default new Command()
    .setDescription("Send notifications")
    .run(async (interaction) => {
        const row = new ActionRowBuilder<MentionableSelectMenu>().addComponents(
            notifySelect.setData({ action: "send_notification" }),
        );
        
        await interaction.reply({
            content: "Select users or roles to notify:",
            components: [row],
        });
    });

Min and Max Values

Control how many mentionables can be selected:

import { MentionableSelectMenu } from "@djs-core/runtime";

export default new MentionableSelectMenu()
    .setPlaceholder("Select 1-3 users or roles")
    .setMinValues(1)
    .setMaxValues(3)
    .run(async (interaction) => {
        const totalSelected = interaction.users.size + interaction.roles.size;
        await interaction.reply(`Selected ${totalSelected} mentionable(s)`);
    });

Disabled Mentionable Select Menu

Mentionable select menus can be disabled:

import { MentionableSelectMenu } from "@djs-core/runtime";

export default new MentionableSelectMenu()
    .setPlaceholder("This menu is disabled")
    .setDisabled(true)
    .run(async (interaction) => {
        await interaction.reply("Menu is disabled");
    });