Skip to content

Reply Building

Note

All event types share the same Reply API. JDA-Commands will always acknowledge the interaction event for you.

Text Messages

The simplest way of sending a reply is using the reply(String) method. This will send a non-ephemeral text message. If the event has already been replied to, this method will edit the original message instead of sending a new one by default.

The reply() method also has some useful overloads, you can find a full list here.

Reply Configuration

You can change this default behaviour by calling with() before sending the reply. This will return a ConfigurableReply object to you, you can use to modify settings:

Ephemeral Reply

event.with().ephemeral(true).reply("Hello World!");

Edit Reply

event.with().editReply(false).reply("Hello World!");

Components

Replying with Components

The ConfigurableReply object is also used to attach components. You reference components by the name of the method they are defined with, just like we did before with modals.

Example

@SlashCommand("greet")
public void onCommand(CommandEvent event) {
    event.with.components("onButton").reply("Hello World!"); //(1)!
}

@Button("Greet me!")
public void onButton(ButtonEvent event) { 
    event.reply("Hello %s".formatted(event.getUser().getAsMention()));
}
  1. We reference the Button we want to send via the method name.

You can also omit the text message and only send the component by calling reply() with no arguments.

Action Rows

Every call to components() will create a new action row. If you want more than one action row you need to call components() multiple times.

Example

event.with().components("firstButton").components("secondButton").reply();

If you want to add multiple components to the same action row, just pass the method names to the same components() call.

Example

event.with.components("firstButton", "secondButton").reply();

Note

One action row supports up to 5 buttons but only 1 select menu.

Enabling & Disabling

By default, all components are enabled. If you want to attach a disabled component, you need to wrap it by calling Component.disabled(methodName).

If you want to add multiple components to the same action row, with some of them enabled and some disabled, you need to wrap all of them.

Example

event.with.components(Component.disabled("firstButton"), Component.enabled("secondButton")).reply();

Keeping Components

When working with components and especially when building menus, e.g. a pagination with buttons, it is often needed to keep the components attached, even when editing the original message multiple times.

Normally, Discord would remove any components when sending a message edit, unless they are explicitly reattached.

JDA-Commands flips this behaviour and will keep your components attached by default.

You can disable this by calling keepComponents(false):

Example

event.with().keepComponents(false).reply("Message edit!");

Alternatively you can call removeComponents() which will remove all components attached to a message.


Cookie Clicker Example

@Interaction
public class CookieClicker {

    private int counter;

    @SlashCommand(value = "cookie clicker", desc = "Play cookie clicker")
    public void onClicker(CommandEvent event) {
        event.with().components("onCookie").reply("You've got %s cookie(s)!", counter);
    }

    @Button(value = "Collect", emoji = "🍪", style = ButtonStyle.SUCCESS)
    public void onCookie(ComponentEvent event) {
        event.reply("You've got %s cookie(s)!", ++counter);
    }
}

Cookie Clicker

Foreign Components

You can attach components that were defined in a different class by using the Component class again. In addition to the method name, you must also pass the class reference in that case.

Example

event.with()
    .components(Component.enabled(ButtonHelpers.class, "onConfirm"), Component.enabled(ButtonHelpers.class, "onDeny"))
    .reply("Are you sure?");

The foreign component will use the original Runtime just like any other component would. If no instance of the class the component is defined in (ButtonHelpers in the example above) exists yet, the Runtime will create one instance (and store it for potential future method calls).

Lifetime

As discussed earlier, Runtimes have a limited lifetime. By default, JDA-Commands will close a Runtime after 15 minutes have passed.

Component Lifetime

This means all components belonging to that Runtime will stop working after 15 minutes!

JDA-Commands will handle this case for you. This error message can be customized.

Expiration Message

If you want to avoid this behaviour, you have to reply with components that are runtime-independent. They will create a new Runtime everytime they are executed. These components will even work after a full bot restart! If you want them to not be usable anymore you need to remove them on your own.

Info

Modals cannot be independent because they always need a parent interaction that triggers them!

Example

event.with().components(Component.independent("onButton")).reply("Hello World!");

Embeds

Failure

The Embed API is currently refactored. This wiki will cover Embeds as soon as the refactoring is done.

ReplyConfig

The @ReplyConfig annotation provides a way to modify the default behaviour for the editReply, ephemeral and keepComponents settings. You can either annotate single methods or entire interaction controllers.

ReplyConfig Annotation

@Interaction
@ReplyConfig(ephemeral = true)
public class InteractionController {

    @SlashCommand("example")
    @ReplyConfig(editReply = false)
    public void onCommand(CommandEvent) {...}

}

Alternatively, you can set a global reply config at the builder:

Global ReplyConfig

JDACommands.builder(jda, Main.class)
    .globalReplyConfig(new ReplyConfig(true, false, false))
    .start();

JDA-Commands will apply clashing ReplyConfigs in the following hierarchy:

  1. with()#... calls
  2. ReplyConfig method annotation
  3. ReplyConfig class annotation
  4. global ReplyConfig