Skip to main content

Buttons

note

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

Creating Buttons#

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

Creating and sending buttons for a regular message#

// Whatever channel you want the message inSnowflake channelId = Snowflake.of(0);
Button button = Button.primary("custom-id", "Click me!!");
client.getChannelById(channelId)    .ofType(GuildMessageChannel.class)    .flatMap(channel -> channel.createMessage(        MessageCreateSpec.builder()        // Buttons must be in action rows        .addComponent(ActionRow.of(button))        .build()    )).subscribe();

Buttons in a component response#

Button button = Button.success("custom-id", "Pong?");
client.on(ChatInputInteractionEvent.class, event -> {    if (event.getCommandName().equals("ping")) {        return event.reply("Pong!")            .withComponents(ActionRow.of(button));    }}).subscribe();

Link Buttons#

You may want to direct a user to a website when they click a button, to do this we use Button.link() as so:

Button button = Button.link("https://discord4j.com", "Discord4J");
caution

Link buttons do not send interaction events when clicked.

Disabled Buttons#

If you want to prevent a button from being used, you can easily set the button to being disabled.

Button button = Button.danger("custom-id", "Danger!!").disabled();

This works for all button styles.

Emoji Buttons#

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);Button customEmoteButton = Button.primary("custom-id", customEmoji);
// Unicode emoteReactionEmoji unicodeEmoji = ReactionEmoji.unicode("\u2764");Button unicodeEmoteButton = Button.secondary("custom-id-2", unicodeEmoji);
note

To get the ID of a specific custom emoji, put the emoji in chat, right click, and click copy link. In that link, is the emoji's ID.

For example, the D4J emote in our server. Its link is: https://cdn.discordapp.com/emojis/546687597246939136.png?v=1 and the ID is 546687597246939136

Using a Temporary Listener To Respond#

note

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

Like Application Commands, buttons are always valid, no matter how much time has passed since the message was created. Responding to a button 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);
Button button = Button.primary("custom-id", "Click me!!");
client.getChannelById(channelId)    .ofType(GuildMessageChannel.class)    .flatMap(channel -> {        Mono<Message> createMessageMono = channel.createMessage(MessageCreateSpec.builder()            .addComponent(ActionRow.of(button))            .build());
        Mono<Void> tempListener = client.on(ButtonInteractionEvent.class, event -> {            if (event.getCustomId().equals("custom-id")) {                return event.reply("You clicked me!").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#