Modals

Modals are dialogs that appear over Discord’s UI to collect structured text input from users. They can contain up to 5 text input fields.

Modals can only be shown in response to an interaction (button click, command, etc.) — they cannot be sent directly in a message.

Creating a modal handler

Create a file in src/components/modals/. Its custom ID is set via .setCustomId() and must match what you use when showing the modal.

import { Modal } from "@djs-core/runtime";
export default new Modal()
.setCustomId("feedback-modal")
.run(async (interaction) => {
const name = interaction.fields.getTextInputValue("name-input");
const feedback = interaction.fields.getTextInputValue("feedback-input");
await interaction.reply({
content: `Thanks ${name}! We received your feedback.`,
ephemeral: true,
});
});

Showing a modal

To display a modal, call interaction.showModal() from a command or button handler. Build it using discord.js’s ModalBuilder:

import { Command } from "@djs-core/runtime";
import { ModalBuilder, TextInputBuilder, TextInputStyle, ActionRowBuilder } from "discord.js";
export default new Command()
.setDescription("Submit feedback")
.run(async (interaction) => {
const modal = new ModalBuilder()
.setCustomId("feedback-modal")
.setTitle("Give us feedback");
const nameInput = new TextInputBuilder()
.setCustomId("name-input")
.setLabel("Your name")
.setStyle(TextInputStyle.Short)
.setRequired(true);
const feedbackInput = new TextInputBuilder()
.setCustomId("feedback-input")
.setLabel("Your feedback")
.setStyle(TextInputStyle.Paragraph)
.setRequired(true);
modal.addComponents(
new ActionRowBuilder<TextInputBuilder>().addComponents(nameInput),
new ActionRowBuilder<TextInputBuilder>().addComponents(feedbackInput),
);
await interaction.showModal(modal);
});

Passing data to a modal

Use .withData<T>() to declare a typed data payload, then .setData() when showing the modal.

import { Modal } from "@djs-core/runtime";
export default new Modal()
.withData<{ targetUserId: string }>()
.setCustomId("edit-nickname")
.run(async (interaction, data) => {
const nickname = interaction.fields.getTextInputValue("nickname-input");
await interaction.guild?.members.edit(data.targetUserId, { nick: nickname });
await interaction.reply({ content: "Nickname updated!", ephemeral: true });
});
import editNicknameModal from "../../components/modals/edit-nickname";
// In a command or button handler:
await interaction.showModal(
editNicknameModal.setData({ targetUserId: interaction.targetUser.id })
);

Data passed via .setData() is stored server-side and retrieved automatically when the modal is submitted. It doesn’t appear in the custom ID visible to the user.