Discord bot modals are pop-up windows that let users fill out forms directly inside Discord. They replace the old method of collecting input through multiple bot messages or long command arguments. Modals support text inputs, short and long paragraphs, and validation before submission. This article explains what modals are, how they work, and how to set them up in your bot code.
Modals were introduced by Discord in 2022 as part of the Interactions API. They allow bots to collect structured data from users without cluttering a channel. You can use modals for sign-up forms, bug reports, polls, or any multi-field input. The form appears over the Discord client, and the user submits it with a single click.
This guide covers the modal structure, required permissions, code examples using discord.py, and common mistakes to avoid. After reading, you will be able to implement a modal that collects user feedback or registration data.
Key Takeaways: Discord Bot Modals for Form Input
- Modal submission via InteractionResponse.send_modal(): Sends a modal form to the user that appears as a pop-up window.
- TextInput with style short or paragraph: Collects single-line or multi-line text from users inside the modal.
- on_modal_submit callback: Handles the data after the user clicks Submit, allowing you to process the input.
What Discord Bot Modals Are and Why You Need Them
Modals are interactive components that let bots display a form with one or more text fields. Unlike slash commands, which accept limited arguments, modals can collect multiple fields in a single interaction. They are triggered by a user action such as a slash command, button click, or select menu choice.
Each modal has a custom ID, a title shown at the top, and one or more TextInput components. Each TextInput has a label, placeholder text, style (short or paragraph), minimum and maximum length, and whether it is required. The user fills in the fields and clicks Submit. The bot receives a modal submit interaction containing all the values.
Modals are useful for any scenario where you need more than one piece of information. For example, a bug report modal can collect the issue title, description, steps to reproduce, and severity level. A registration modal can collect username, email, and role preference. Because the form appears in a pop-up, the user stays in the same channel and does not see multiple bot messages.
To use modals, your bot must have the applications.commands scope enabled. This is already required for slash commands. No additional bot permissions are needed for modals themselves, but the bot must be able to send messages in the channel where the modal is triggered.
Steps to Create and Handle a Discord Bot Modal
The following steps assume you have a bot set up with discord.py version 2.0 or later. Older versions do not support modals. You also need to enable the message_content intent if your bot uses prefix commands to trigger the modal, but modal triggers via slash commands do not require that intent.
- Import modal classes from discord.ui
In your bot code, import Modal and TextInput from discord.ui. Also import Interaction and AppCommand if you are using slash commands. Example:from discord.ui import Modal, TextInput. - Define a modal class that inherits from discord.ui.Modal
Create a new class, for example FeedbackModal. Inside the class, define TextInput variables as class attributes. Each TextInput requires a label, placeholder, style (discord.TextStyle.short or discord.TextStyle.paragraph), min_length, max_length, and required (True or False). You can also set a default value. Example:name = TextInput(label="Your name", placeholder="John Doe", style=discord.TextStyle.short, required=True). - Override the on_submit method
Inside your modal class, define async def on_submit(self, interaction: Interaction):. This method runs when the user clicks Submit. Access the values using self.children[index].value or by referencing the attribute name directly, like self.name.value. Process the data as needed, then send a response with interaction.response.send_message(). - Add a slash command that sends the modal
Create a slash command using @bot.tree.command(). Inside the command, call await interaction.response.send_modal(FeedbackModal()). The modal will appear to the user immediately. Example:@bot.tree.command(name="feedback", description="Submit feedback using a modal")thenasync def feedback(interaction: Interaction): await interaction.response.send_modal(FeedbackModal()). - Sync the command tree
In your bot startup code, call await bot.tree.sync() to register the slash command with Discord. You only need to sync once per bot startup unless you change commands frequently during development. After syncing, the command appears in Discord servers where your bot has the applications.commands scope.
Common Mistakes and Limitations When Using Modals
Modal does not appear when user runs the command
The most common cause is that the bot code throws an exception before calling send_modal(). Check your console for errors. Another cause is that the modal class is defined incorrectly — ensure it inherits from discord.ui.Modal and that all TextInput attributes are defined at the class level, not inside __init__. Also verify that the bot has the applications.commands scope in the server.
Modal submission fails silently
If the on_submit method raises an exception, the user sees a generic error pop-up. Wrap the code in on_submit inside a try-except block and use interaction.response.send_message() to inform the user of the error. Also ensure that on_submit always sends a response — either with send_message, edit_original_response, or defer. If you do not respond within 3 seconds, the interaction expires and the user sees a failure.
TextInput values are empty even though user filled them
This happens when you access self.children[index].value but the index is wrong. Access values by attribute name instead: self.name.value. Also ensure that the TextInput attributes are defined before __init__ is called. If you define them inside __init__, they will not be recognized as modal components.
Modal has too many fields or long labels
Discord limits modals to 5 TextInput components. Each label can be up to 45 characters. Placeholder text can be up to 100 characters. The title can be up to 45 characters. If you exceed these limits, the modal will not send and an error will be logged. Plan your form fields carefully.
User cannot interact with the modal after it is dismissed
Modals are ephemeral — once the user closes or submits them, they cannot reopen the same modal instance. If the user needs to edit their input, your bot must provide a new command or button to trigger the modal again. You cannot edit a modal after it is sent.
| Item | Slash Command Arguments | Modal Form |
|---|---|---|
| Number of fields | Up to 25 optional arguments | Up to 5 TextInput components |
| Field types | String, integer, boolean, user, channel, role, mentionable | Short text or paragraph text only |
| User experience | Typed in chat bar, limited by Discord UI | Pop-up window with labels and placeholders |
| Validation | Basic type validation by Discord | Custom validation in on_submit method |
| Best for | Quick single-input commands | Multi-field forms with structured data |
Modals are a powerful way to collect form input from Discord users. They keep the interface clean and allow for complex data collection without cluttering the chat. You can now create a modal for feedback, registration, or any multi-field input. To extend your bot, try adding a button that opens the modal instead of a slash command. A practical next step is to store the submitted data in a database or send it to a webhook for processing.