Role panel
A panel where every member picks their roles. Each role is a Section with a button next to it, and a menu at the end handles colors.
{ "flags": 32768, "components": [ { "type": 17, "accent_color": 15418782, "components": [ { "type": 10, "content": "## 🎭 Pick your roles\nClick a button to add or remove the role." }, { "type": 14 }, { "type": 9, "components": [ { "type": 10, "content": "🎮 **Gamer**\n-# Access to the gaming channels" } ], "accessory": { "type": 2, "style": 2, "label": "Gamer", "custom_id": "role:111111111111111111" } }, { "type": 9, "components": [ { "type": 10, "content": "🎨 **Artist**\n-# Share your drawings" } ], "accessory": { "type": 2, "style": 2, "label": "Artist", "custom_id": "role:222222222222222222" } }, { "type": 9, "components": [ { "type": 10, "content": "📢 **Announcements**\n-# Get pinged on every announcement" } ], "accessory": { "type": 2, "style": 2, "label": "Announcements", "custom_id": "role:333333333333333333" } }, { "type": 14, "spacing": 2 }, { "type": 10, "content": "**Name color**" }, { "type": 1, "components": [ { "type": 3, "custom_id": "color", "placeholder": "Pick a color", "min_values": 0, "options": [ { "label": "Red", "value": "444444444444444444", "emoji": { "name": "🔴" } }, { "label": "Green", "value": "555555555555555555", "emoji": { "name": "🟢" } }, { "label": "Blue", "value": "666666666666666666", "emoji": { "name": "🔵" } } ] } ] } ] } ]}The logic
Section titled “The logic”- Each button’s
custom_idisrole:+ the role ID. That way a single handler covers all of them. - On click: if the member has the role, remove it; otherwise, add it.
- Reply with an ephemeral message to confirm (only the clicker sees it).
- The panel doesn’t change, so there’s no need to edit it.
Handler code
Section titled “Handler code”- Read
data.custom_idand extract the role ID. - Add the role with
PUT /guilds/{guild.id}/members/{user.id}/roles/{role.id}or remove it withDELETEon the same route. - Respond to the interaction with
type: 4andflags: 32832(V2 + ephemeral).
client.on(Events.InteractionCreate, async (interaction) => { if (!interaction.isButton() || !interaction.customId.startsWith('role:')) return;
const roleId = interaction.customId.split(':')[1]; const member = interaction.member; let text;
if (member.roles.cache.has(roleId)) { await member.roles.remove(roleId); text = `➖ Role <@&${roleId}> removed.`; } else { await member.roles.add(roleId); text = `➕ Role <@&${roleId}> added.`; }
await interaction.reply({ flags: MessageFlags.IsComponentsV2 | MessageFlags.Ephemeral, components: [new TextDisplayBuilder().setContent(text)], allowedMentions: { parse: [] }, });});@client.eventasync def on_interaction(interaction: discord.Interaction): if interaction.type != discord.InteractionType.component: return custom_id = interaction.data.get("custom_id", "") if not custom_id.startswith("role:"): return
role = interaction.guild.get_role(int(custom_id.split(":")[1])) member = interaction.user
if role in member.roles: await member.remove_roles(role) text = f"➖ Role {role.mention} removed." else: await member.add_roles(role) text = f"➕ Role {role.mention} added."
view = discord.ui.LayoutView() view.add_item(discord.ui.TextDisplay(text)) await interaction.response.send_message(view=view, ephemeral=True)s.AddHandler(func(s *discordgo.Session, i *discordgo.InteractionCreate) { if i.Type != discordgo.InteractionMessageComponent { return } customID := i.MessageComponentData().CustomID if !strings.HasPrefix(customID, "role:") { return }
roleID := strings.TrimPrefix(customID, "role:") text := "➕ Role <@&" + roleID + "> added."
if slices.Contains(i.Member.Roles, roleID) { s.GuildMemberRoleRemove(i.GuildID, i.Member.User.ID, roleID) text = "➖ Role <@&" + roleID + "> removed." } else { s.GuildMemberRoleAdd(i.GuildID, i.Member.User.ID, roleID) }
s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{ Flags: discordgo.MessageFlagsIsComponentsV2 | discordgo.MessageFlagsEphemeral, Components: []discordgo.MessageComponent{discordgo.TextDisplay{Content: text}}, }, })})