# Discord Interactions

This page covers the button-to-modal text input and the single and multi select menus in `core/discord`, and how each answer reaches your `Reply` handler.

All three methods take `(ctx, channelID, replyTo, text string, ...)`, return the prompt `*discordgo.Message`, and reject an empty channel ID or prompt text. A non-empty `replyTo` attaches the prompt as a reply. Each prompt gets a UUID that is embedded in its component custom ID (`go-bot:input:...` or `go-bot:select:menu:...`) and used as the key of its in-memory state. Components with other custom IDs are left to other handlers.

## Free-text input: SendInput

```go
prompt, err := bot.SendInput(ctx, in.ChannelID, in.MessageID, "What is your name?")
```

Discord can only open a modal in response to an interaction, so the input takes two steps:

| Step | Behavior |
|---|---|
| Send | The prompt text with one **Input** button |
| Button click | The library opens a modal titled with the first 45 bytes of the prompt, containing one required short text field labelled **Input** |
| Submit | The library acknowledges with an ephemeral `✓` and deletes that acknowledgement, removes the state, then calls `Reply` with `Text` = the answer and `MessageID` = the prompt ID |

The button stays on the prompt after submit. Clicking it again, or submitting after `Close()`, answers with an ephemeral `Expired`. The 45-byte title cut counts bytes, so a multi-byte prompt can be cut inside a character; keep prompts short or put the question in the message text.

## Single select: SendSelect

```go
prompt, err := bot.SendSelect(ctx, in.ChannelID, in.MessageID, "Pick a color", []string{"Red", "Green", "Blue"})
```

A native string select menu (placeholder `Select (single-select)`, min 1, max 1) with one option per non-empty item; the label and value are both the item. 1 to 25 items are allowed. When the user picks, the library acknowledges without changing the message, removes the state, and calls `Reply` with `Text` = the picked value.

## Multi select: SendMultiSelect

```go
prompt, err := bot.SendMultiSelect(ctx, in.ChannelID, in.MessageID, "Pick toppings", []string{"Cheese", "Ham", "Olive"})
```

The same menu with placeholder `Select (multi-select)`, min 0, and max equal to the number of options. Discord submits once when the user closes the dropdown, and the library calls `Reply` with `CallbackPicks` = the chosen values (`Text` stays empty).

## After an answer

The menu stays visible after a pick, but its state is gone, so a second pick gets an ephemeral `Expired`. The library leaves the prompt in place on purpose: replacing the message to strip the components would require sending content, and discordgo serializes an empty content field that Discord rejects with error 50006. Remove the prompt with `bot.Delete(ctx, in.ChannelID, in.MessageID)`; for modal and select answers, `in.MessageID` is the prompt ID.

## Related pages

- [Reply Handler](/reply-handler)
- [Discord Setup](/discord) (`Input` fields)
- [Telegram Interactions](/telegram-interactions) (the Telegram equivalents)
