Skip to content

Buttons and menus

A message sent by a command can have buttons and menus. When someone uses one, the same command runs again, and it knows which button it was. That way one command holds a whole system: the message, its buttons, and what each one does.

{{ if eq .Trigger "command" }}
{{ sendMessage nil (complexMessage
"content" "Do you like pizza?"
"components" (cslice (crow
(cbutton "label" "Yes" "id" "yes" "style" "success")
(cbutton "label" "No" "id" "no" "style" "danger")))) }}
{{ return }}{{ end }}
{{/* From here on, a button was used */}}
{{ respond (printf "You pressed **%s**." .Button.ID) true }}
  • .Trigger says why the code is running: "command" (someone typed the command), "button" or "select" (someone used a button or a menu).
  • .Button.ID is the "id" of the button that was used, and .Button.Data is its "data".
  • For a menu, .Values is the list of the options that were chosen.
  • {{ return }} ends the code, so the part for the command does not run when a button is used.

cbutton makes a button from pairs of a name and a value.

Name Value
label The text of the button, up to 80 characters
emoji An emoji such as "👆", instead of or together with the label
id The name of the button, 1 to 20 letters, numbers, - or _. Required, unless it has a url
data Extra text for the button, up to 20 letters, numbers, ., - or _. It comes back in .Button.Data
style "primary", "secondary" (the default), "success" or "danger"
url Makes a link button. It starts with http:// or https://, and it has no id: it just opens the link
disabled true for a button that cannot be used
user A user ID. Only that member can use the button; anyone else is told “This is not for you”

A button needs a label or an emoji.

A menu of options, from pairs of a name and a value.

Name Value
id The name of the menu, as for a button. Required
options A list of options, each one cslice "label" "value" or cslice "label" "value" "description". From 1 to 25
placeholder The text shown when nothing is chosen, up to 150 characters
min, max How many options can be chosen. By default 1 and 1
user A user ID, like in a button
{{ sendMessage nil (complexMessage "components" (cslice (crow
(cselect "id" "pick" "placeholder" "Choose one" "options" (cslice
(cslice "Pizza" "pizza" "Cheesy")
(cslice "Sushi" "sushi")))))) }}

When a menu is used, .Values holds the value of each option that was chosen, for example (index .Values 0).

crow puts components in a row. A row holds up to 5 buttons, or one menu by itself. A message holds up to 5 rows:

"components" (cslice (crow button1 button2) (crow menu))

A button or a menu can open a modal, a form with text fields that pops up over Discord. When the person sends it, the same command runs again, with what they wrote.

{{ if eq .Trigger "command" }}
{{ sendMessage nil (complexMessage "content" "Have an idea?" "components" (cslice (crow
(cbutton "label" "Suggest" "id" "open" "style" "primary")))) }}
{{ return }}{{ end }}
{{ if eq .Trigger "button" }}
{{ showModal (cmodal "id" "send" "title" "Your suggestion" "fields" (cslice
(ctext "id" "title" "label" "Title" "max" 80)
(ctext "id" "details" "label" "Details" "style" "paragraph" "required" false))) }}
{{ return }}{{ end }}
{{/* From here on, the form was sent */}}
{{ respond (printf "You wrote: **%s**" .Fields.title) true }}
  • .Trigger is "modal" when the form was sent. .Modal.ID is the "id" of the modal and .Modal.Data its "data".
  • .Fields holds what was written, by the id of each field: .Fields.title, .Fields.details. A field left empty is an empty text.
  • showModal only works when the command runs because of a button or a menu. A modal cannot open another modal, and a command typed in chat cannot open one.
  • respond answers the form, in private with true. updateMessage changes the message the button was on.
  • Opening the modal is the answer to the click, so a run can use showModal or respond/updateMessage, not both.
Name Value
id The name of the modal, as for a button. Required
title The title at the top, up to 45 characters. Required
fields A list of 1 to 5 fields made with ctext. Required
data Extra text, like the data of a button. It comes back in .Modal.Data
Name Value
id The name of the field, 1 to 20 letters, numbers or _. Required. It is how .Fields finds it
label The text above the field, up to 45 characters. Required
style "short" (one line, the default) or "paragraph" (many lines)
placeholder A hint shown while the field is empty, up to 100 characters
value Text the field starts with, up to 4000 characters
required false lets the person leave it empty. By default it is required
min, max The least and the most characters, from 0 to 4000

When a button or a menu is used, the person is waiting for an answer. In the code of a button you can:

Function What it does
respond message Answers the click with a new message, seen by everyone
respond message true The same, but only the person who clicked sees it
updateMessage message Changes the message the button is on. What you do not give stays: if you only give an embed, the buttons stay
Printing text If the code prints text and does not use respond or updateMessage, that text is the answer

If the code does none of those, the click is simply acknowledged and nothing is shown. Only one of respond and updateMessage can be used in a run.

message is a text, a cembed or a complexMessage, like in Embeds and messages. It can also hold new "components".

The other actions (addRole, sendMessage…) work in a click too, for the person who clicked, with the same checks.

Everything in Data is there, about the person who clicked, plus:

  • .Message.ID, .Message.Content and .Message.Embeds (a list of maps with Title, Description, Footer, Author, AuthorIcon, FooterIcon, Thumbnail, Image and Color) of the message the button is on.
  • .Trigger, .Button and .Values, as above. When a modal was sent, .Modal and .Fields.

.Args is empty in a click.

  • A button keeps working as long as the command exists and has code. If the command is removed, the click answers “That command does not exist anymore.”
  • Using the same button twice in a row in a very short time is ignored.
  • Direct messages cannot have buttons or menus.
  • Each handler runs with the same limits as a command.
  • Use stored data to remember what people chose. The id of the message (.Message.ID) is a good key for things that belong to one message, such as a vote.

The vote template is a yes or no vote where each person has one vote and can change it. Install it with !customcommand template vote and read its code with !customcommand codeshow vote.