All about selects
Welcome, this post is about the different types of select menus and how to use them.
This post shows how to define the different types of select menus, and how to use them.
Select
(technically called a “string select”) This is the most basic select menu, it allows the user to select from a list of custom provided options. Note: You can only have up to 25 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...",
# our options
options=[
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]
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
andmax_values
kwargs. - You can choose the type of channels that are shown. (ChannelSelect)
- You can specify the options that should be selected by default using the
default_values
kwarg. (requires discord.py v2.4+) - 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.
Code is mostly the same as the example above, except we 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[Union[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.
Code is mostly the same as the example above, except we use RoleSelect
instead of Select
:
from discord.ui import RoleSelect
And values
is a list of discord.Role
objects:
from typing import Any, List
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.
Code is mostly the same as the example above, except we 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, List, Union
async def callback(self, interaction: discord.Interaction) -> Any:
mentionables: List[Union[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"{interaction.user.mention} selected 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.
Code is mostly the same as the example above, except we 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, List, Union
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[Union[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.
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.
from typing inport 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:
from typing inport 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:
...