Modals & Select Menus
Select menus
Section titled “Select menus”cordless has builders for all five Discord select menu kinds: StringSelect, where you supply the options, and four “entity” selects that resolve to real Discord objects: UserSelect, RoleSelect, ChannelSelect, MentionableSelect.
from cordless import StringSelect, SelectOption, ActionRow
@bot.command("class", description="Pick a class")async def pick_class(ctx): await ctx.send( "Choose your class:", components=[ActionRow([ StringSelect("class_select", [ SelectOption("Warrior", "warrior", description="Tank"), SelectOption("Mage", "mage", description="Ranged damage"), ]) ])], )
@bot.select("class_select")async def class_selected(ctx): choice = ctx.values[0] # ctx.values is always a list, even for single-select await ctx.edit(content=f"You picked {choice}!")Entity selects work the same way, just without an options list. Discord resolves the user’s picks for you:
from cordless import UserSelect, RoleSelect, ChannelSelect, MentionableSelect
UserSelect("pick_user", placeholder="Choose a member")RoleSelect("pick_role", min_values=1, max_values=3)ChannelSelect("pick_channel", channel_types=[0, 2]) # text, voiceMentionableSelect("pick_anyone")ctx.values holds the selected ids for every select type. min_values/max_values (both default 1) control how many picks are required/allowed: set max_values above 1 for multi-select.
Deferred selects
Section titled “Deferred selects”Same as buttons: set defer=True for select handlers that take a while:
@bot.select("slow_select", defer=True)async def slow_select(ctx): ...Modals
Section titled “Modals”Modals pop up a form. Build one with Modal and one or more TextInput fields, and send it with ctx.send_modal(). This must be the first response to the interaction (you can’t defer, then show a modal):
from cordless import Modal, TextInput, TextInputStyle
@bot.command("feedback", description="Leave feedback")async def feedback(ctx): await ctx.send_modal(Modal( "feedback_modal", "Send Feedback", TextInput("summary", "Summary", style=TextInputStyle.SHORT), TextInput("details", "Details", style=TextInputStyle.PARAGRAPH, required=False), ))
@bot.modal("feedback_modal")async def feedback_submitted(ctx): summary = ctx.modal_values["summary"] details = ctx.modal_values["details"] await ctx.send(f"Thanks! Got: {summary}")ctx.modal_values is a flat dict of custom_id → submitted value for every field in the modal.
TextInput(custom_id, label, style=1, min_length=None, max_length=None, required=True, value=None, placeholder=None): style is TextInputStyle.SHORT (single line) or TextInputStyle.PARAGRAPH (multi-line); value pre-fills the field.
Deferred modal submissions
Section titled “Deferred modal submissions”@bot.modal("slow_modal", defer=True)async def slow_modal(ctx): ...