All about selects
Welcome, this post is about the different types of select menus and how to use them. View in discord.py docs
Select #
(technically called a “string select”) This is the most basic select menu, it allows the user to select from a list of (up to 25) custom provided options.
Example:
from typing import Any
import discord
from discord.ui import Select
class FruitSelect(Select):
def __init__(self):
super().__init__(
placeholder="Select a favorite fruit...",
# the options
options=[
# value is what is returned when the option is selected, label is what is shown to the user
# value is optional, if not provided, label is used as the value
discord.SelectOption(label="Apple", value="apple"),
discord.SelectOption(label="Orange", value="orange"),
discord.SelectOption(label="Banana", value="banana"),
]
)
async def callback(self, interaction: discord.Interaction) -> Any:
selected_fruit: str = self.values[0] # either "apple", "orange" or "banana"
await interaction.response.send_message(
f"{interaction.user.mention}'s favorite fruit is {selected_fruit}!"
)
Sending that as a view will result in a select menu that looks like this:
Auto populated selects #
discord.py v2.1+ required
These are select menus that are populated automatically by Discord, they are not really customizable:
- You can not filter the members, roles or channels shown.
- You can set the min/max amount of options the user can or must choose using the
min_values
(1-25) andmax_values
(1-25) kwargs. - You can choose the type of channels that are shown for ChannelSelect.
- You can specify the options that should be selected by default using the
default_values
kwarg. (requires discord.py v2.4+) (more on later) - Only the first 25 options will be shown, the rest can be searched for using the search bar, which has auto-complete.
UserSelect #
This is a select menu that allows the user to select from a list of members in the server. Or, if used in a DM, you and the bot.
Same as the basic select, except we import and use UserSelect
instead of Select
:
from discord.ui import UserSelect
And values
is a list of discord.Member
or discord.User
objects:
from typing import Any
async def callback(self, interaction: discord.Interaction) -> Any:
users: list[discord.Member | discord.User] = self.values
selected_users = [
f"Name: {user.name}, ID: {user.id}"
for user in users
]
await interaction.response.send_message(
f"{interaction.user.mention} selected the following users:\n" + "\n".join(selected_users)
)
RoleSelect #
This is a select menu that allows the user to select from a list of roles in the server.
Same as the basic select, except we import and use RoleSelect
instead of Select
:
from discord.ui import RoleSelect
And values
is a list of discord.Role
objects:
from typing import Any
async def callback(self, interaction: discord.Interaction) -> Any:
roles: list[discord.Role] = self.values
selected_roles = [
f"Name: {role.name}, ID: {role.id}"
for role in roles
]
await interaction.response.send_message(
f"{interaction.user.mention} selected the following roles:\n" + "\n".join(selected_roles)
)
MentionableSelect #
This is a select menu that allows the user to select from a list of members and roles in the server. Or, if used in a DM, you and the bot.
Same as the basic select, except we import and use MentionableSelect
instead of Select
:
from discord.ui import MentionableSelect
And values
is a list of discord.Member
, discord.User
and discord.Role
objects:
from typing import Any
async def callback(self, interaction: discord.Interaction) -> Any:
mentionables: list[discord.Member | discord.User | discord.Role] = self.values
selected_users = [
f"Name: {user.name}, ID: {user.id}"
for user in mentionables
if isinstance(user, (discord.Member, discord.User))
]
selected_roles = [
f"Name: {role.name}, ID: {role.id}"
for role in mentionables
if isinstance(role, discord.Role)
]
await interaction.response.send_message(
(
f"{interaction.user.mention} selected the following users:\n" + "\n".join(selected_users)
f"\nand the following roles:\n" + "\n".join(selected_roles)
)
)
ChannelSelect #
This is a select menu that allows the user to select from a list of channels in the server.
Same as the basic select, except we import and use ChannelSelect
instead of Select
and we can use the channel_types
kwarg to limit the type of channels shown, all channels are shown by default:
from discord import ChannelType
from discord.app_commands import AppCommandChannel, AppCommandThread
from discord.ui import ChannelSelect
And values
is a list of discord.AppCommandChannel
or discord.AppcommandThread
objects:
from typing import Any
class ChannelsSelector(ChannelSelect):
def __init__(self):
super().__init__(
placeholder="Select a channel...",
# limit the type of channels shown to text, voice and threads
channel_types=[ChannelType.text, ChannelType.voice, ChannelType.thread]
async def callback(self, interaction: discord.Interaction) -> Any:
channels: list[AppCommandChannel | AppCommandThread] = self.values
selected_channels = [
f"Name: {channel.name}, ID: {channel.id}"
for channel in channels
]
await interaction.response.send_message(
f"{interaction.user.mention} selected the following channels:\n" + "\n".join(selected_channels)
)
default_values #
discord.py v2.4+ required
This was briefly mentioned above, but you can specify the options that should be selected by default using the default_values
kwarg.
The kwarg takes a list of objects, the type of which depends on the type of select menu, e.g. for a ChannelSelect
it would be a list of channel objects.
There is also special class for it called SelectDefaultValue
which takes the id
of a user, role of channel and the type
of the object or you can also use the from_user
, from_role
and from_channel
classmethods to create the object. This one can be used for all the types of selects.
from typing import Any
import discord
from discord import ui
class ChooseAnyoneExceptMe(ui.View):
def __init__(self, bot_owner_id: int):
super().__init__()
# set the default values of the user select to the bot owner, so they can't select me!
self.user_select.default_values = [
discord.SelectDefaultValue(id=bot_owner_id, type=discord.SelectDefaultType.user)
]
@ui.select(cls=ui.UserSelect, placeholder="Select my owner...")
async def user_select(self, interaction: discord.Interaction, select: ui.UserSelect) -> Any:
selected_user = select.values[0]
# yes, we are very sure that the selected user is not the bot owner.
await interaction.response.send_message(
f"{selected_user.mention} is not my owner!"
)
Decorator #
The select menus can also be defined using a decorator in a View
subclass and specifying the cls
kwarg (defaults to Select
):
from typing import Any
from discord import ui
class SelectView(ui.View):
# string select
# @ui.select(placeholder="Select an option...". options=[...])
# or @ui.select(cls=ui.Select, placeholder="Select an option...". options=[...])
# user select
# @ui.select(cls=ui.UserSelect, placeholder="Select a user...")
# role select
# @ui.select(cls=ui.RoleSelect, placeholder="Select a role...")
# mentionable select
# @ui.select(cls=ui.MentionableSelect, placeholder="Select a role or user...")
# channel select
# only text, voice and threads are shown
@ui.select(cls=ui.ChannelSelect, channel_types=[ChannelType.text, ChannelType.voice, ChannelType.thread], placeholder="Select a channel...")
async def channel_select(self, interaction: discord.Interaction, select: ui.ChannelSelect) -> Any:
...