Overview
Modals are popup forms that appear when triggered by an interaction. They allow you to collect text input from users in a structured format, similar to Discord’s native ban or server creation dialogs.
Creating Modals
Modal.create()
Create a new modal builder.
The custom ID used to identify this modal (max 100 characters)
The title displayed at the top of the modal (max 45 characters)
static Builder create(@Nonnull String customId, @Nonnull String title)
Example: Basic Modal
public void onSlashCommandInteraction(@Nonnull SlashCommandInteractionEvent event)
{
if (event.getName().equals("modmail"))
{
TextInput subject = TextInput.create("subject", TextInputStyle.SHORT)
.setPlaceholder("Subject of this ticket")
.setMinLength(10)
.setMaxLength(100) // or setRequiredRange(10, 100)
.build();
TextInput body = TextInput.create("body", TextInputStyle.PARAGRAPH)
.setPlaceholder("Your concerns go here")
.setMinLength(30)
.setMaxLength(1000)
.build();
Modal modal = Modal.create("modmail", "Modmail")
.addComponents(Label.of("Subject", subject), Label.of("Body", body))
.build();
event.replyModal(modal).queue();
}
}
Building Modals
addComponents()
Add components to the modal (max 5 components).
components
ModalTopLevelComponent...
required
The components to add (typically TextInput fields with Labels)
Builder addComponents(@Nonnull ModalTopLevelComponent... components)
Example: Multi-Field Modal
TextInput name = TextInput.create("name", TextInputStyle.SHORT)
.setLabel("Name")
.setPlaceholder("Enter your name")
.setRequired(true)
.build();
TextInput email = TextInput.create("email", TextInputStyle.SHORT)
.setLabel("Email")
.setPlaceholder("[email protected]")
.setRequired(true)
.build();
TextInput message = TextInput.create("message", TextInputStyle.PARAGRAPH)
.setLabel("Message")
.setPlaceholder("What would you like to say?")
.setMinLength(20)
.setMaxLength(1000)
.build();
Modal modal = Modal.create("contact", "Contact Form")
.addComponents(
Label.of("Name", name),
Label.of("Email", email),
Label.of("Message", message)
)
.build();
event.replyModal(modal).queue();
Text Input Components
TextInput.create()
Create a text input field.
The custom ID for this text input
The input style (SHORT for single line, PARAGRAPH for multi-line)
TextInput.create(@Nonnull String customId, @Nonnull TextInputStyle style)
setLabel()
Set the label shown above the input field.
The label text (max 45 characters)
TextInput.Builder setLabel(@Nonnull String label)
setPlaceholder()
Set placeholder text shown when the input is empty.
The placeholder text (max 100 characters)
TextInput.Builder setPlaceholder(@Nullable String placeholder)
setMinLength() / setMaxLength()
Set length constraints for the input.
TextInput.Builder setMinLength(int minLength)
TextInput.Builder setMaxLength(int maxLength)
setRequired()
Set whether this field must be filled out.
Whether the field is required (default: true)
TextInput.Builder setRequired(boolean required)
setValue()
Set a pre-filled value for the input.
TextInput.Builder setValue(@Nullable String value)
SHORT
Single-line text input for short responses.
TextInput input = TextInput.create("username", TextInputStyle.SHORT)
.setLabel("Username")
.setMaxLength(32)
.build();
PARAGRAPH
Multi-line text input for longer responses.
TextInput input = TextInput.create("feedback", TextInputStyle.PARAGRAPH)
.setLabel("Feedback")
.setMinLength(50)
.setMaxLength(2000)
.build();
Handling Modal Submissions
onModalInteraction()
Listen for modal submission events.
@Override
public void onModalInteraction(ModalInteractionEvent event) {
if (event.getModalId().equals("modmail")) {
String subject = event.getValue("subject").getAsString();
String body = event.getValue("body").getAsString();
// Process the modal data
processModmail(subject, body);
event.reply("Thank you for your submission!")
.setEphemeral(true)
.queue();
}
}
Getting Values
ModalInteraction.java:88-94
default ModalMapping getValue(@Nonnull String customId) {
Checks.notNull(customId, "ID");
return getValues().stream()
.filter(mapping -> mapping.getCustomId().equals(customId))
.findFirst()
.orElse(null);
}
@Override
public void onModalInteraction(ModalInteractionEvent event) {
if (event.getModalId().equals("contact")) {
String name = event.getValue("name").getAsString();
String email = event.getValue("email").getAsString();
String message = event.getValue("message").getAsString();
// Validate email
if (!email.contains("@")) {
event.reply("Invalid email address!")
.setEphemeral(true)
.queue();
return;
}
// Save to database
saveContactForm(name, email, message);
event.reply("Your message has been sent! We'll get back to you soon.")
.setEphemeral(true)
.queue();
}
}
Modal Properties
getId()
Get the modal’s custom ID.
getTitle()
Get the modal’s title.
@Nonnull
String getTitle()
getComponents()
Get the list of components in this modal.
@Nonnull
List<ModalTopLevelComponentUnion> getComponents()
ModalMapping
getAsString()
Get the submitted value as a string.
getCustomId()
Get the custom ID of this input field.
getType()
Get the component type.
Replying with Modals
Modals can only be sent as a reply to certain interactions.
From Slash Commands
@Override
public void onSlashCommandInteraction(SlashCommandInteractionEvent event) {
if (event.getName().equals("feedback")) {
Modal modal = createFeedbackModal();
event.replyModal(modal).queue();
}
}
@Override
public void onButtonInteraction(ButtonInteractionEvent event) {
if (event.getComponentId().equals("report")) {
Modal modal = createReportModal();
event.replyModal(modal).queue();
}
}
@Override
public void onStringSelectInteraction(StringSelectInteractionEvent event) {
if (event.getComponentId().equals("support-topic")) {
String topic = event.getValues().get(0);
Modal modal = createSupportModal(topic);
event.replyModal(modal).queue();
}
}
Editing Messages After Modal
If a modal was shown in response to a component interaction, you can edit the original message.
@Override
public void onModalInteraction(ModalInteractionEvent event) {
if (event.getModalId().equals("edit-message")) {
String newContent = event.getValue("content").getAsString();
// Edit the original message that had the button
event.deferEdit().queue();
event.getHook().editOriginal(newContent).queue();
}
}
Constants
Modal.MAX_COMPONENTS - Maximum of 5 components per modal
Modal.MAX_ID_LENGTH - 100 characters for custom IDs
Modal.MAX_TITLE_LENGTH - 45 characters for modal titles
TextInput.MAX_LABEL_LENGTH - 45 characters for input labels
TextInput.MAX_PLACEHOLDER_LENGTH - 100 characters for placeholders
TextInput.MAX_VALUE_LENGTH - 4000 characters for input values
Best Practices
Use SHORT style for single-line inputs like names, usernames, or short answers. Use PARAGRAPH style for longer text like feedback, descriptions, or messages.
You must respond to modal interactions within 3 seconds using reply(), deferReply(), deferEdit(), or editMessage(). Otherwise, the interaction will fail.
Modals can only be shown as a response to interactions - you cannot send them in regular messages. They must be triggered by slash commands, buttons, or select menus.
Set appropriate min/max length constraints to guide users and prevent invalid submissions. For example, require at least 20 characters for meaningful feedback.