Skip to main content

Select Menus

note

This page is a continuation of the Interactions (Reference) which dives into what Interactions are.

Creating Select Menus#

Creating Select Menus is extremely easy with Discord4J. You can add select menus to any message the bot sends, including responses to application commands or other interactions!

Creating and sending select menus for a regular message#

// Whatever channel you want the message inSnowflake channelId = Snowflake.of(0);
SelectMenu select = SelectMenu.of("custom-id",    SelectMenu.Option.of("label", "value"),    SelectMenu.Option.of("label2", "value2"),    SelectMenu.Option.of("label3", "value2"));
client.getChannelById(channelId)    .ofType(GuildMessageChannel.class)    .flatMap(channel -> channel.createMessage(        MessageCreateSpec.builder()        .content("Select Something!")        // Select Menus must be in action rows        .addComponent(ActionRow.of(select))        .build()    )).subscribe();

Select menus in a component response#

SelectMenu select = SelectMenu.of("custom-id",    SelectMenu.Option.of("label", "value"),    SelectMenu.Option.of("label2", "value2"),    SelectMenu.Option.of("label3", "value2"));
client.on(ChatInputInteractionEvent.class, event -> {    if (event.getCommandName().equals("ping")) {        return event.reply("Pong!")            .withComponents(ActionRow.of(select));    }}).subscribe();

Setting how many values a user may pick#

Sometimes you may want to have a select menu where a user can pick multiple values rather than just one. To set a minimum amount of values a user must pick: .withMinValues(AMOUNT) And to set a maximum amount of values a user can pick: .withMaxValues(AMOUNT)

These methods can be used together to enable more complex select menu actions:

SelectMenu select = SelectMenu.of("custom-id",    SelectMenu.Option.ofDefault("default-label", "Default Value!"),    SelectMenu.Option.of("label", "value"),    SelectMenu.Option.of("label2", "value2")).withMaxValues(3).withMinValues(1);

Disabled select menus#

If you want to prevent a select menu from being used, you can easily set it to being disabled.

SelectMenu select = SelectMenu.of("custom-id",    SelectMenu.Option.ofDefault("default-label", "Default Value!"),    SelectMenu.Option.of("label", "value"),    SelectMenu.Option.of("label2", "value2")).disabled();

Placeholder text#

Placeholder text can be used when you don't wish to have a default selected value. This text will appear when no value is selected and can easily be done like so:

SelectMenu select = SelectMenu.of("custom-id",    SelectMenu.Option.of("label", "value"),    SelectMenu.Option.of("label2", "value2")).withPlaceholder("Please select an option <3");

Default selected value#

You may want to have a default value selected for the user, luckily discord supports this and D4J implements this cleanly. All you need to do is create an option as follows:

SelectMenu.Option.ofDefault("default-label", "Default Value!")

Adding descriptions to options#

Helping users understand the options they are picking is important. Sometimes, the context is clear and a description is unneeded, but if there needs to be a description, this can easily be achieved.

SelectMenu.Option option = SelectMenu.Option.of("Label", "value").withDescription("My Description");

Emoji options#

If you want an emoji displayed rather than a text label we would use the following code:

// Custom non-animated emoteReactionEmoji customEmoji = ReactionEmoji.of(546687597246939136L, "d4j", false);SelectMenu.Option customEmoteOption = SelectMenu.Option.of("label", "value").withEmoji(customEmoji);
// Unicode emoteReactionEmoji unicodeEmoji = ReactionEmoji.unicode("\u2764");SelectMenu.Option unicodeEmoteOption = SelectMenu.Option.of("label", "value").withEmoji(unicodeEmoji);

Using a Temporary Listener To Respond#

note

If you would like to always respond to select menu interactions, you can easily do so by creating a custom listener just as we showed in Application Commands - Receiving, using the SelectMenuInteractionEvent class.

Like Application Commands, select menus are always valid, no matter how much time has passed since the message was created. Responding to a select menu days, or weeks after its creation may not always be feasible. To counteract this, we can create a temporary listener that automatically times out.

// Whatever channel you want the message inSnowflake channelId = Snowflake.of(0);
SelectMenu select = SelectMenu.of("custom-id",    SelectMenu.Option.of("label", "value"),    SelectMenu.Option.of("label2", "value2")).withPlaceholder("Please select an option <3");
client.getChannelById(channelId)    .ofType(GuildMessageChannel.class)    .flatMap(channel -> {        Mono<Message> createMessageMono = channel.createMessage(MessageCreateSpec.builder()            .addComponent(ActionRow.of(select))            .build());
        Mono<Void> tempListener = client.on(SelectMenuInteractionEvent.class, event -> {            if (event.getCustomId().equals("custom-id")) {                //Get all selected values                String values = event.getValues().toString().replace("[", "").replace("]", "");                return event.reply("You selected these values: " + values).withEphemeral(true);            } else {                // Ignore it                return Mono.empty();            }        }).timeout(Duration.ofMinutes(30)) // Timeout after 30 minutes        // Handle TimeoutException that will be thrown when the above times out        .onErrorResume(TimeoutException.class, ignore -> Mono.empty())        .then(); //Transform the flux to a mono
        //Return both of the monos together        return createMessageMono.then(tempListener);    }).subscribe();

Further Reading#