Java Discord API - A comprehensive Java library for building Discord bots and applications
—
Modern Discord interactions including slash commands, buttons, select menus, modals, and context menus with full builder pattern support.
Modern command system using Discord's native slash command interface.
/**
* Represents a slash command interaction.
*/
interface SlashCommandInteraction extends IReplyCallback {
/** Get command name */
String getName();
/** Get full command string with options */
String getCommandString();
/** Get command ID */
long getCommandIdLong();
String getCommandId();
/** Get subcommand name (if used) */
String getSubcommandName();
/** Get subcommand group name (if used) */
String getSubcommandGroup();
/** Get all command options */
List<OptionMapping> getOptions();
/** Get option by name */
OptionMapping getOption(String name);
/** Get option by name with type checking */
OptionMapping getOption(String name, OptionType type);
/** Get options for subcommand */
List<OptionMapping> getOptionsByName(String name);
/** Get options by type */
List<OptionMapping> getOptionsByType(OptionType type);
}
/**
* Represents an option value in a slash command.
*/
interface OptionMapping {
/** Get option name */
String getName();
/** Get option type */
OptionType getType();
/** Get raw string value */
String getAsString();
/** Get as boolean */
boolean getAsBoolean();
/** Get as long */
long getAsLong();
/** Get as double */
double getAsDouble();
/** Get as snowflake */
IMentionable getAsMentionable();
/** Get as user */
User getAsUser();
/** Get as member */
Member getAsMember();
/** Get as role */
Role getAsRole();
/** Get as channel */
GuildChannel getAsChannel();
/** Get as message channel */
MessageChannel getAsMessageChannel();
/** Get as attachment */
Message.Attachment getAsAttachment();
}
/**
* Utility class for creating command data.
*/
class Commands {
/** Create slash command */
static SlashCommandData slash(String name, String description);
/** Create user context menu command */
static CommandData user(String name);
/** Create message context menu command */
static CommandData message(String name);
}
/**
* Builder for slash command data.
*/
interface SlashCommandData extends CommandData {
/** Add string option */
SlashCommandData addOption(OptionType type, String name, String description);
SlashCommandData addOption(OptionType type, String name, String description, boolean required);
SlashCommandData addOption(OptionType type, String name, String description, boolean required, boolean autoComplete);
/** Add options */
SlashCommandData addOptions(OptionData... options);
SlashCommandData addOptions(Collection<? extends OptionData> options);
/** Add subcommand */
SlashCommandData addSubcommands(SubcommandData... subcommands);
SlashCommandData addSubcommands(Collection<? extends SubcommandData> subcommands);
/** Add subcommand group */
SlashCommandData addSubcommandGroups(SubcommandGroupData... groups);
SlashCommandData addSubcommandGroups(Collection<? extends SubcommandGroupData> groups);
}
/**
* Builder for command options.
*/
class OptionData {
/** Create option */
OptionData(OptionType type, String name, String description);
OptionData(OptionType type, String name, String description, boolean required);
OptionData(OptionType type, String name, String description, boolean required, boolean autoComplete);
/** Set option as required */
OptionData setRequired(boolean required);
/** Set option as auto-complete */
OptionData setAutoComplete(boolean autoComplete);
/** Add string choice */
OptionData addChoice(String name, String value);
/** Add number choice */
OptionData addChoice(String name, long value);
OptionData addChoice(String name, double value);
/** Add choices */
OptionData addChoices(Command.Choice... choices);
OptionData addChoices(Collection<? extends Command.Choice> choices);
/** Set channel types (for channel options) */
OptionData setChannelTypes(ChannelType... channelTypes);
OptionData setChannelTypes(Collection<ChannelType> channelTypes);
/** Set number range */
OptionData setRequiredRange(long min, long max);
OptionData setRequiredRange(double min, double max);
/** Set string length range */
OptionData setRequiredLength(int min, int max);
}Usage Examples:
import net.dv8tion.jda.api.interactions.commands.build.Commands;
import net.dv8tion.jda.api.interactions.commands.build.OptionData;
import net.dv8tion.jda.api.interactions.commands.OptionType;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
// Register slash commands
jda.updateCommands().addCommands(
Commands.slash("ping", "Check bot latency"),
Commands.slash("userinfo", "Get information about a user")
.addOption(OptionType.USER, "user", "Target user", false),
Commands.slash("ban", "Ban a user from the server")
.addOption(OptionType.USER, "user", "User to ban", true)
.addOption(OptionType.STRING, "reason", "Reason for ban", false)
.addOption(OptionType.INTEGER, "days", "Days of messages to delete", false)
.setDefaultPermissions(DefaultMemberPermissions.enabledFor(Permission.BAN_MEMBERS)),
Commands.slash("poll", "Create a poll")
.addOption(OptionType.STRING, "question", "Poll question", true)
.addOption(OptionType.STRING, "option1", "First option", true)
.addOption(OptionType.STRING, "option2", "Second option", true)
.addOption(OptionType.STRING, "option3", "Third option", false)
).queue();
// Handle slash command interactions
public class SlashCommandHandler extends ListenerAdapter {
@Override
public void onSlashCommandInteraction(SlashCommandInteractionEvent event) {
switch (event.getName()) {
case "ping" -> {
long gatewayPing = event.getJDA().getGatewayPing();
event.reply("Gateway ping: " + gatewayPing + "ms").queue();
}
case "userinfo" -> {
User target = event.getOption("user", event.getUser(), OptionMapping::getAsUser);
Member member = event.getGuild().getMember(target);
EmbedBuilder embed = new EmbedBuilder()
.setTitle("User Information")
.addField("Username", target.getName(), true)
.addField("ID", target.getId(), true)
.addField("Created", target.getTimeCreated().format(DateTimeFormatter.RFC_1123_DATE_TIME), false)
.setThumbnail(target.getEffectiveAvatarUrl());
if (member != null) {
embed.addField("Joined", member.getTimeJoined().format(DateTimeFormatter.RFC_1123_DATE_TIME), false);
embed.addField("Roles", member.getRoles().stream()
.map(Role::getAsMention)
.collect(Collectors.joining(", ")), false);
}
event.replyEmbeds(embed.build()).queue();
}
case "ban" -> {
User target = event.getOption("user", OptionMapping::getAsUser);
String reason = event.getOption("reason", "No reason provided", OptionMapping::getAsString);
int days = event.getOption("days", 0, OptionMapping::getAsInt);
event.getGuild().ban(target, days, TimeUnit.DAYS)
.reason(reason)
.queue(
success -> event.reply("Successfully banned " + target.getAsTag()).setEphemeral(true).queue(),
error -> event.reply("Failed to ban user: " + error.getMessage()).setEphemeral(true).queue()
);
}
}
}
}Interactive button components in messages for user interaction.
/**
* Represents a button interaction event.
*/
interface ButtonInteraction extends IMessageEditCallback {
/** Get button that was clicked */
Button getButton();
/** Get button component ID */
String getComponentId();
/** Get message containing the button */
Message getMessage();
/** Get button style */
ButtonStyle getStyle();
/** Get button label */
String getLabel();
/** Get button emoji */
Emoji getEmoji();
}
/**
* Button component builder.
*/
class Button {
/** Create primary button */
static Button primary(String id, String label);
static Button primary(String id, Emoji emoji);
static Button primary(String id, String label, Emoji emoji);
/** Create secondary button */
static Button secondary(String id, String label);
static Button secondary(String id, Emoji emoji);
static Button secondary(String id, String label, Emoji emoji);
/** Create success button (green) */
static Button success(String id, String label);
static Button success(String id, Emoji emoji);
static Button success(String id, String label, Emoji emoji);
/** Create danger button (red) */
static Button danger(String id, String label);
static Button danger(String id, Emoji emoji);
static Button danger(String id, String label, Emoji emoji);
/** Create link button */
static Button link(String url, String label);
static Button link(String url, Emoji emoji);
static Button link(String url, String label, Emoji emoji);
/** Get button properties */
String getId();
String getLabel();
ButtonStyle getStyle();
Emoji getEmoji();
String getUrl();
boolean isDisabled();
/** Create disabled/enabled versions */
Button asDisabled();
Button asEnabled();
/** Modify button properties */
Button withId(String id);
Button withLabel(String label);
Button withEmoji(Emoji emoji);
Button withStyle(ButtonStyle style);
Button withUrl(String url);
Button withDisabled(boolean disabled);
}Usage Examples:
import net.dv8tion.jda.api.interactions.components.ActionRow;
import net.dv8tion.jda.api.interactions.components.buttons.Button;
import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent;
// Send message with buttons
Button acceptButton = Button.success("accept", "Accept");
Button declineButton = Button.danger("decline", "Decline");
Button infoButton = Button.secondary("info", "More Info");
channel.sendMessage("Do you want to join the event?")
.setComponents(ActionRow.of(acceptButton, declineButton, infoButton))
.queue();
// Handle button interactions
public class ButtonHandler extends ListenerAdapter {
@Override
public void onButtonInteraction(ButtonInteractionEvent event) {
String componentId = event.getComponentId();
switch (componentId) {
case "accept" -> {
event.reply("✅ You have accepted the invitation!").setEphemeral(true).queue();
// Disable the buttons after interaction
List<ActionRow> updatedRows = event.getMessage().getActionRows().stream()
.map(row -> ActionRow.of(row.getComponents().stream()
.map(component -> {
if (component instanceof Button button) {
return button.asDisabled();
}
return component;
})
.collect(Collectors.toList())))
.collect(Collectors.toList());
event.getHook().editOriginalComponents(updatedRows).queue();
}
case "decline" -> {
event.reply("❌ You have declined the invitation.").setEphemeral(true).queue();
}
case "info" -> {
EmbedBuilder embed = new EmbedBuilder()
.setTitle("Event Information")
.setDescription("This is a community gaming event")
.addField("Date", "Tomorrow at 8 PM", true)
.addField("Duration", "2 hours", true)
.setColor(Color.BLUE);
event.replyEmbeds(embed.build()).setEphemeral(true).queue();
}
}
}
}Dropdown selection components for multiple choice interactions.
/**
* Represents a select menu interaction.
*/
interface SelectMenuInteraction extends IMessageEditCallback {
/** Get selected values */
List<String> getValues();
/** Get selected options */
List<SelectOption> getSelectedOptions();
/** Get select menu component */
SelectMenu getSelectMenu();
/** Get component ID */
String getComponentId();
/** Get message containing the select menu */
Message getMessage();
}
/**
* String select menu builder.
*/
class StringSelectMenu {
/** Create string select menu builder */
static StringSelectMenu.Builder create(String customId);
static class Builder {
/** Set placeholder text */
Builder setPlaceholder(String placeholder);
/** Set value range */
Builder setRequiredRange(int min, int max);
Builder setMinValues(int min);
Builder setMaxValues(int max);
/** Add option */
Builder addOption(String label, String value);
Builder addOption(String label, String value, String description);
Builder addOption(String label, String value, String description, Emoji emoji);
Builder addOption(String label, String value, String description, boolean defaultValue);
/** Add options */
Builder addOptions(SelectOption... options);
Builder addOptions(Collection<? extends SelectOption> options);
/** Set as disabled */
Builder setDisabled(boolean disabled);
/** Build the select menu */
StringSelectMenu build();
}
}
/**
* Entity select menu for Discord entities.
*/
class EntitySelectMenu {
/** Create entity select menu builder */
static EntitySelectMenu.Builder create(String customId, SelectTarget target);
enum SelectTarget {
USER, ROLE, MENTIONABLE, CHANNEL
}
static class Builder {
/** Set placeholder text */
Builder setPlaceholder(String placeholder);
/** Set value range */
Builder setRequiredRange(int min, int max);
Builder setMinValues(int min);
Builder setMaxValues(int max);
/** Set channel types (for channel select) */
Builder setChannelTypes(ChannelType... types);
Builder setChannelTypes(Collection<ChannelType> types);
/** Set default values */
Builder setDefaultValues(SelectOption... options);
Builder setDefaultValues(Collection<? extends SelectOption> options);
/** Set as disabled */
Builder setDisabled(boolean disabled);
/** Build the select menu */
EntitySelectMenu build();
}
}
/**
* Select option builder.
*/
class SelectOption {
/** Create select option */
static SelectOption of(String label, String value);
static SelectOption of(String label, String value, String description);
static SelectOption of(String label, String value, String description, Emoji emoji);
/** Get option properties */
String getLabel();
String getValue();
String getDescription();
Emoji getEmoji();
boolean isDefault();
/** Create modified versions */
SelectOption withLabel(String label);
SelectOption withValue(String value);
SelectOption withDescription(String description);
SelectOption withEmoji(Emoji emoji);
SelectOption withDefault(boolean defaultValue);
}Usage Examples:
import net.dv8tion.jda.api.interactions.components.selections.StringSelectMenu;
import net.dv8tion.jda.api.interactions.components.selections.SelectOption;
import net.dv8tion.jda.api.events.interaction.component.StringSelectInteractionEvent;
// Create select menu
StringSelectMenu gameMenu = StringSelectMenu.create("game-select")
.setPlaceholder("Choose your favorite games")
.setRequiredRange(1, 3)
.addOptions(
SelectOption.of("Minecraft", "minecraft")
.withDescription("Block building sandbox game")
.withEmoji(Emoji.fromUnicode("🧱")),
SelectOption.of("Valorant", "valorant")
.withDescription("Tactical shooter game")
.withEmoji(Emoji.fromUnicode("🔫")),
SelectOption.of("League of Legends", "lol")
.withDescription("MOBA game")
.withEmoji(Emoji.fromUnicode("⚔️")),
SelectOption.of("Among Us", "amongus")
.withDescription("Social deduction game")
.withEmoji(Emoji.fromUnicode("👾"))
)
.build();
channel.sendMessage("What games do you play?")
.setComponents(ActionRow.of(gameMenu))
.queue();
// Handle select menu interactions
public class SelectMenuHandler extends ListenerAdapter {
@Override
public void onStringSelectInteraction(StringSelectInteractionEvent event) {
if (event.getComponentId().equals("game-select")) {
List<String> selectedGames = event.getValues();
String response = "You selected: " + String.join(", ", selectedGames);
// Get role assignments based on games
List<Role> rolesToAdd = new ArrayList<>();
Guild guild = event.getGuild();
for (String game : selectedGames) {
Role gameRole = guild.getRolesByName(game + "-player", true).stream()
.findFirst()
.orElse(null);
if (gameRole != null) {
rolesToAdd.add(gameRole);
}
}
if (!rolesToAdd.isEmpty()) {
Member member = event.getMember();
guild.modifyMemberRoles(member, rolesToAdd, null)
.queue(success -> {
event.reply(response + "\n🎮 Game roles have been assigned!").setEphemeral(true).queue();
});
} else {
event.reply(response).setEphemeral(true).queue();
}
}
}
}Form-based interactions for collecting user input through text fields.
/**
* Represents a modal form interaction.
*/
interface ModalInteraction extends IReplyCallback {
/** Get modal ID */
String getModalId();
/** Get value by component ID */
ModalMapping getValue(String id);
/** Get all input values */
List<ModalMapping> getValues();
}
/**
* Represents a modal input value.
*/
interface ModalMapping {
/** Get component ID */
String getId();
/** Get input type */
TextInput.InputType getType();
/** Get input value */
String getAsString();
}
/**
* Modal builder.
*/
class Modal {
/** Create modal builder */
static Modal.Builder create(String id, String title);
static class Builder {
/** Add text input component */
Builder addActionRows(ActionRow... actionRows);
Builder addActionRows(Collection<? extends ActionRow> actionRows);
/** Add components */
Builder addComponents(ItemComponent... components);
/** Build the modal */
Modal build();
}
}
/**
* Text input component for modals.
*/
class TextInput {
/** Create short text input */
static TextInput.Builder create(String id, String label, InputType style);
enum InputType {
SHORT, PARAGRAPH
}
static class Builder {
/** Set placeholder text */
Builder setPlaceholder(String placeholder);
/** Set as required */
Builder setRequired(boolean required);
/** Set default value */
Builder setValue(String value);
/** Set length range */
Builder setRequiredRange(int min, int max);
Builder setMinLength(int min);
Builder setMaxLength(int max);
/** Build the text input */
TextInput build();
}
}Usage Examples:
import net.dv8tion.jda.api.interactions.modals.Modal;
import net.dv8tion.jda.api.interactions.components.text.TextInput;
import net.dv8tion.jda.api.interactions.components.text.TextInputStyle;
import net.dv8tion.jda.api.events.interaction.ModalInteractionEvent;
// Create and show modal
public void showFeedbackModal(SlashCommandInteractionEvent event) {
TextInput subject = TextInput.create("subject", "Subject", TextInputStyle.SHORT)
.setPlaceholder("Brief summary of your feedback")
.setMaxLength(100)
.setRequired(true)
.build();
TextInput feedback = TextInput.create("feedback", "Feedback", TextInputStyle.PARAGRAPH)
.setPlaceholder("Detailed feedback...")
.setMaxLength(1000)
.setRequired(true)
.build();
Modal modal = Modal.create("feedback-modal", "Submit Feedback")
.addActionRows(ActionRow.of(subject), ActionRow.of(feedback))
.build();
event.replyModal(modal).queue();
}
// Handle modal interactions
public class ModalHandler extends ListenerAdapter {
@Override
public void onModalInteraction(ModalInteractionEvent event) {
if (event.getModalId().equals("feedback-modal")) {
String subject = event.getValue("subject").getAsString();
String feedback = event.getValue("feedback").getAsString();
// Process feedback
EmbedBuilder embed = new EmbedBuilder()
.setTitle("Feedback Received")
.addField("Subject", subject, false)
.addField("Feedback", feedback, false)
.addField("User", event.getUser().getAsTag(), true)
.addField("Guild", event.getGuild().getName(), true)
.setTimestamp(Instant.now())
.setColor(Color.GREEN);
// Send to feedback channel
TextChannel feedbackChannel = event.getGuild().getTextChannelsByName("feedback", true).stream()
.findFirst()
.orElse(null);
if (feedbackChannel != null) {
feedbackChannel.sendMessageEmbeds(embed.build()).queue();
}
event.reply("Thank you for your feedback! We'll review it soon.").setEphemeral(true).queue();
}
}
}Right-click context menu commands for users and messages.
/**
* User context menu interaction.
*/
interface UserContextInteraction extends IReplyCallback {
/** Get target user */
User getTarget();
/** Get target member */
Member getTargetMember();
}
/**
* Message context menu interaction.
*/
interface MessageContextInteraction extends IReplyCallback {
/** Get target message */
Message getTarget();
}Usage Examples:
// Register context menu commands
jda.updateCommands().addCommands(
Commands.user("Get Avatar"),
Commands.message("Report Message")
).queue();
// Handle context menu interactions
public class ContextMenuHandler extends ListenerAdapter {
@Override
public void onUserContextInteraction(UserContextInteractionEvent event) {
if (event.getName().equals("Get Avatar")) {
User target = event.getTarget();
EmbedBuilder embed = new EmbedBuilder()
.setTitle(target.getName() + "'s Avatar")
.setImage(target.getEffectiveAvatarUrl() + "?size=256")
.setColor(Color.BLUE);
event.replyEmbeds(embed.build()).queue();
}
}
@Override
public void onMessageContextInteraction(MessageContextInteractionEvent event) {
if (event.getName().equals("Report Message")) {
Message target = event.getTarget();
// Create report modal
TextInput reason = TextInput.create("reason", "Reason", TextInputStyle.PARAGRAPH)
.setPlaceholder("Why are you reporting this message?")
.setRequired(true)
.build();
Modal modal = Modal.create("report-modal", "Report Message")
.addActionRows(ActionRow.of(reason))
.build();
event.replyModal(modal).queue();
}
}
}// Option types for slash commands
enum OptionType {
SUB_COMMAND, SUB_COMMAND_GROUP, STRING, INTEGER, BOOLEAN, USER, CHANNEL, ROLE, MENTIONABLE, NUMBER, ATTACHMENT
}
// Button styles
enum ButtonStyle {
PRIMARY, SECONDARY, SUCCESS, DANGER, LINK
}
// Text input styles
enum TextInputStyle {
SHORT, PARAGRAPH
}
// Interaction context types
enum InteractionContextType {
GUILD, BOT_DM, PRIVATE_CHANNEL
}
// Default member permissions
class DefaultMemberPermissions {
static DefaultMemberPermissions ENABLED;
static DefaultMemberPermissions DISABLED;
static DefaultMemberPermissions enabledFor(Permission... permissions);
static DefaultMemberPermissions enabledFor(Collection<Permission> permissions);
}Install with Tessl CLI
npx tessl i tessl/maven-net-dv8tion--jda