Welcome, this post is about the different types of select menus and how to use them.

View Documentation

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: string_select

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 and max_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:
        ...