Concepts
Forms
Pop up a form with text boxes, then do something with what the user typed.
A form (Discord calls it a modal) is a pop-up window with text boxes. Use it when you need longer answers, like an application, a report or feedback.
A form has two parts:
- Open the form. From a command or a button click.
- Handle the answers. In a Modal Submit event.
1. Build and open the form#
In a slash command:
- Under Behavior, turn off Show "thinking…". A form must be the first answer to the command.
- In the Pre-hook, build the form and open it:
form = ModalBuilder(title="Staff application", custom_id="apply")
form.add_text_input("age", "How old are you?", max_length=3)
form.add_text_input("why", "Why do you want to join?", style="long")
await send_modal(form)
end()end() stops the normal reply. The form is the reply.
Text box options#
form.add_text_input(
name,
label,
style="short",
placeholder=UNDEFINED,
value=UNDEFINED,
required=True,
min_length=0,
max_length=4000,
)UNDEFINED means "not set". Leave those out unless you need them.
| Option | What it does |
|---|---|
name | The key you read the answer with later. |
label | The question shown above the box. |
style | "short" for one line, "long" for a big box. |
placeholder | Grey hint text inside the box. |
value | Text already filled in. |
required | Set False to allow an empty answer. |
min_length, max_length | Shortest and longest answer allowed. |
Discord allows at most 5 text boxes in one form.
2. Handle the answers#
Make an event:
- Type: Modal Submit
- Custom ids:
apply(the samecustom_idas the form)
defer_response(ephemeral=True)
age = values.get("age", "")
why = values.get("why", "")
send_message("applications", f"New application from {user.mention}\nAge: {age}\nWhy: {why}")
respond_interaction(interaction, "Thanks! Your application was sent.")values holds every answer, by the name you gave each text box.
Answer fast
Discord waits 3 seconds. Call defer_response(...) first, then do the work, then respond_interaction(...).
Open a form from a button#
In a Button Click event, open the form as the first answer. Do not defer before it.
form = ModalBuilder(title="Report a user", custom_id="report")
form.add_text_input("details", "What happened?", style="long")
await send_modal(form)Inside a View, pass the click as the second argument:
@button(label="Apply", custom_id="apply_btn")
async def apply(self, interaction, component):
await send_modal(form, interaction)Without the second argument, the form tries to answer the command again, and Discord refuses it.
Full list of form functions: Forms reference.