Use the smallest interaction that does the job
| Control | Use it for | Example |
|---|---|---|
| Slash command | Starting a task with structured inputs | /remind time message |
| Button | A clear next action | Confirm, cancel, next page |
| Select menu | Choosing from known options | Pick a channel or category |
| Modal | Collecting longer or structured input | Describe a bug or submit feedback |
| Context-menu command | Acting on a user or message | Report this message |
Use familiar verbs and put required inputs first. Prefer a channel or role picker over asking people to paste an ID. If a command needs several paragraphs of instructions, split it into smaller steps.
Reply before the interaction expires
Discord requires an initial response within three seconds. If work takes longer, defer promptly and then edit the reply. Interaction tokens can be used for follow-ups for 15 minutes. See the interaction response reference.
This handler fragment assumes MessageFlags is imported from discord.js and that createReport has a timeout. Use private replies for account details or setup errors that only the requester needs to see.
Open a modal as the initial response
a common mistake
Do not defer and then try to open a modal.
Showing the modal is itself the initial response. Prepare the form quickly, show it, and handle the later submission as a new interaction.
The user runs /feedback
Show a short form with a clear title and only the fields needed to understand the issue.The user submits the form
Validate the values and permissions again. If saving takes time, defer this new submission interaction.Confirm what happened
Say whether feedback was saved and where any reply will arrive. Preserve useful input if an error requires the user to try again.
Component layouts and supported modal fields evolve. Check the component reference for your chosen layout rather than applying older message-row limits to every component.
Treat every click as a new request
- Check the user, server, and permissions on the server before applying a change.
- Use a short-lived identifier for saved interaction state; do not put secrets in custom IDs.
- Make repeated clicks safe and disable controls once their action is complete.
- Confirm destructive actions with the target and effect spelled out.
- Handle expired controls with a clear way to start again.
A hidden button or a command’s default permissions is not enough to authorize a sensitive operation. Permissions may have changed since the message was sent.
Test the awkward cases
Try the flow on mobile, with a long channel name, with missing permissions, and after the bot restarts. Click twice. Open an old message. Cancel halfway through. These cases reveal more than repeatedly testing the happy path.
Keep the final reply specific: “Reminder saved for Friday at 18:00” is more useful than “Success.” For access checks, see Discord permissions explained.