Category: Discord Bot Tutorials

Discord Bot Tutorial#6Implementing a Dropdown (Select Menu)!

This post was translated from the Korean original.

Contents8 sections

Hi there! This is Mojangcam 😎

In Part #5, we learned how to interact with a bot using buttons, right? This time we're going one step further and building a dropdown menu (Select Menu)!

Buttons are great when you have 2 or 3 choices, but once you have 5 or more, your screen fills up with buttons. That's where a dropdown menu comes in: it lets you fit up to 25 choices neatly into a single menu. You'll see it used all the time for role pickers, polls, game server selection menus, and more!

📌 What You Need

  • Python 3.8 or later
  • discord.py 2.x (Select Menus are supported starting from 2.0!)
  • A bot token + the bot already invited to your server (see Part 1 of the series!)
Terminal
pip install -U discord.py

You can check your version with pip show discord.py. If it's 2.x or later, you're good! It won't work on 1.x.

📌 Step 1 - Creating the Select (Dropdown) Class

The core of a dropdown is the discord.ui.Select class. You subclass it and define the choices (SelectOption) and what happens when someone makes a choice (callback).

Python
import discord
from discord.ext import commands

class GameSelect(discord.ui.Select):
    def __init__(self):
        options = [
            discord.SelectOption(label="Minecraft", value="minecraft", description="A world built from blocks", emoji="⛏️"),
            discord.SelectOption(label="ARK: Survival", value="ark", description="Survive alongside dinosaurs!", emoji="🦖"),
            discord.SelectOption(label="Valorant", value="valorant", description="5v5 tactical FPS", emoji="🔫"),
        ]
        super().__init__(
            placeholder="Choose your favorite game!",
            min_values=1,
            max_values=1,
            options=options,
        )

    async def callback(self, interaction: discord.Interaction):
        await interaction.response.send_message(
            f"🎮 {interaction.user.mention} chose **{self.values[0]}**!"
        )

Let's break it down piece by piece 💡

  • SelectOption : each individual choice shown in the dropdown. label is the name shown on screen, value is the value your code receives, description is the gray description text, and emoji is the emoji shown in front.
  • placeholder : the hint text shown when nothing is selected yet.
  • min_values / max_values : the minimum and maximum number of choices. Set max_values=3 and it becomes a multi-select menu! (up to 25)
  • callback : the function that runs when the user finishes choosing. The selected values come in through the self.values list.

📌 Step 2 - Putting It in a View

As we learned in the button part, every UI component has to be put in a container called a View before you send it.

Python
class GameSelectView(discord.ui.View):
    def __init__(self):
        super().__init__(timeout=60)  # disable after 60 seconds
        self.add_item(GameSelect())

By the way, a single dropdown takes up an entire row of the View. A View can have up to 5 rows, so you can put up to 5 dropdowns in one View.

📌 Step 3 - Sending It with a Slash Command

Python
intents = discord.Intents.default()
bot = commands.Bot(command_prefix="!", intents=intents)

@bot.event
async def on_ready():
    await bot.tree.sync()
    print(f"✅ {bot.user} bot is ready!")

@bot.tree.command(name="게임선택", description="Pick your favorite game!")
async def game_select(interaction: discord.Interaction):
    await interaction.response.send_message("Make your choice below! 👇", view=GameSelectView())

bot.run("Token")

📌 Full Code (Copy-Paste OK)

Python
# discord.py 2.x / Python 3.8+
import discord
from discord.ext import commands

class GameSelect(discord.ui.Select):
    def __init__(self):
        options = [
            discord.SelectOption(label="Minecraft", value="Minecraft", description="A world built from blocks", emoji="⛏️"),
            discord.SelectOption(label="ARK: Survival", value="ARK: Survival", description="Survive alongside dinosaurs!", emoji="🦖"),
            discord.SelectOption(label="Valorant", value="Valorant", description="5v5 tactical FPS", emoji="🔫"),
        ]
        super().__init__(placeholder="Choose your favorite game!", min_values=1, max_values=1, options=options)

    async def callback(self, interaction: discord.Interaction):
        await interaction.response.send_message(
            f"🎮 {interaction.user.mention} chose **{self.values[0]}**!"
        )

class GameSelectView(discord.ui.View):
    def __init__(self):
        super().__init__(timeout=60)
        self.add_item(GameSelect())

intents = discord.Intents.default()
bot = commands.Bot(command_prefix="!", intents=intents)

@bot.event
async def on_ready():
    await bot.tree.sync()
    print(f"✅ {bot.user} bot is ready!")

@bot.tree.command(name="게임선택", description="Pick your favorite game!")
async def game_select(interaction: discord.Interaction):
    await interaction.response.send_message("Make your choice below! 👇", view=GameSelectView())

bot.run("Token")

📌 Result

When you type /게임선택 (game select), the bot sends a message with a dropdown attached, and when you pick a game from the menu, it replies with "🎮 OO chose Minecraft!"

💡 Bonus: there are also dedicated dropdowns for picking users, roles, and channels! With discord.ui.UserSelect, discord.ui.RoleSelect, and discord.ui.ChannelSelect, you don't have to build the choices yourself. The server's user/role/channel list shows up automatically. I'll cover these in detail when I get the chance!

📌 Common Errors

1. This interaction failed

This happens when the callback doesn't respond within 3 seconds. If your processing takes a while, call await interaction.response.defer() first, then reply with interaction.followup.send().

2. The dropdown is grayed out and disabled

Once the View(timeout=60) time runs out, the component expires. If the menu needs to keep working, set timeout=None. (To keep it working even after the bot restarts, you need a persistent view + a custom_id, which I'll cover in an advanced part!)

3. TypeError: __init__() got an unexpected keyword argument 'options'

You get this error when you pass options to a dedicated select like UserSelect instead of discord.ui.Select. When you define your own choices, always use the basic discord.ui.Select.

📌 Wrapping Up

Today we learned how to neatly fit up to 25 choices into a dropdown (Select Menu). We've gone from buttons to dropdowns, so in the next part we'll cover how to get text input directly from users with a Modal! Stay tuned 🙌

📚 Discord Bot Tutorial Series

  1. Mastering Slash Commands
  2. Adding Options (Arguments) to Slash Commands
  3. Adding Subcommands to Slash Commands
  4. Sending Embeds with Slash Commands
  5. Implementing Button Interactions
  6. Implementing a Dropdown (Select Menu) ← You are here!

Series · Part 6 of 32

Discord Bot Tutorial

  1. #1Discord Bot Tutorial - Mastering Slash Commands!
  2. #2Adding Options (Arguments) to Slash Commands!
  3. #3Adding Subcommands to Slash Commands!
  4. #4Sending Embeds with Slash Commands!
  5. #5Implementing Button Interactions!
  6. #6Implementing a Dropdown (Select Menu)!You are here
  7. #7Getting User Input with a Modal (Python Example)
  8. #8Styling Embeds with Images and Fields (Python Example)
  9. #9Connecting AI (Claude & ChatGPT API) to Your Bot! (Python Example)
  10. #10Adding Multi-Language (i18n) Support! (Python Example)
  11. #11Building a Web Dashboard with Flask! (Python Example)
  12. #12Managing Command Cooldowns and Permissions! (Python Example)
  13. #13Automating Roles and Channels to Manage Your Server! (Python Example)
  14. #14Saving Data! JSON vs SQLite (Python Example)
  15. #15슬래시 명령어 그룹(Group)으로 명령어 정리하기! (파이썬 예제) (Korean)
  16. #16리마인더·알림 기능 만들기! 봇이 먼저 말 걸게 하기 (파이썬 예제) (Korean)
  17. #17RAG로 문서 기반 답변봇 만들기! 우리 서버 전용 FAQ 봇 (파이썬 예제) (Korean)
  18. #18투표(Poll) 기능 만들기! 다수결로 정하는 서버 규칙 (파이썬 예제) (Korean)
  19. #19Cog로 코드 쪼개기! 1000줄 봇도 안 더러워지는 구조 (파이썬 예제) (Korean)
  20. #20자동 환영 메시지·온보딩 만들기! 규칙 동의 버튼으로 자동 역할 부여 (파이썬 예제) (Korean)
  21. #21키워드 자동응답·금지어 필터 만들기! 경고 누적으로 자동 제재까지 (파이썬 예제) (Korean)
  22. #22슬래시 명령어 자동완성(Autocomplete) 만들기! 금지어를 골라서 추가·삭제 (파이썬 예제) (Korean)
  23. #23aiosqlite로 비동기 DB 제대로 설계하기! JSON 탈출 (파이썬 예제) (Korean)
  24. #24채널 난독화(Channel Obfuscation) 대응하기! 11/16부터 안 보이는 채널이 생겨요 (파이썬 예제) (Korean)
  25. #25봇이 죽지 않게! 에러 핸들링·로깅 체계 잡기 (파이썬 예제) (Korean)
  26. #26티켓(Ticket) 문의 시스템 만들기! 버튼 하나로 1:1 상담 채널 자동 생성 (파이썬 예제) (Korean)
  27. #27티켓 담당자 배정·우선순위 만들기! 스태프가 여러 명이어도 안 꼬이게 (파이썬 예제) (Korean)
  28. #28레벨·경험치(XP) 시스템 만들기! 채팅할수록 레벨업, 랭킹판까지 (파이썬 예제) (Korean)
  29. #29화폐·상점(Economy) 시스템 만들기! 코인 벌어서 아이템 사기 (파이썬 예제) (Korean)
  30. #30Build a Poll & Survey Bot! Native Polls + Buttons with Real-Time Tallies (Python Example) 🗳️
  31. #32Build a Server Log & Audit Log Channel! Auto-Log Message Deletes, Edits, Joins/Leaves, and Kicks (Python Example) 🕵️
  32. #33임시 음성방 확장, 파티방 만들기! 방장 위임·강퇴·초대 전용(비공개) 방 + 전용 채팅방 자동 생성 (파이썬 예제) 🎉 (Korean)
Show all 32Collapse

Author

Mojangcam

A hands-on dev and IT log: code I write, servers I run, and the errors I fix along the way.