Skip to content

Instantly share code, notes, and snippets.

@lykn
Last active April 16, 2024 05:39
Show Gist options
  • Star 55 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save lykn/bac99b06d45ff8eed34c2220d86b6bf4 to your computer and use it in GitHub Desktop.
Save lykn/bac99b06d45ff8eed34c2220d86b6bf4 to your computer and use it in GitHub Desktop.
A gist which shows/tells you how to make buttons using discord.py v2(version 2.0.0a)

Note: Before we go any further. Let me make this real clear that the following gist uses the OFFICIAL discord.py library and not forks like discord_components, nextcord, etc... So when your using this code but a different library and fuck up don't comment something mean or go to a help channel in the server and say "this gist is misleading" or "bad gist who wrote this" when your at fault, trust me I'm going to fuck you up😅

Just a reminder^^

Related Links:

DPY's Docs

Discord's Docs

Code(GitHub)

Python

Python(Downloads)

Buttons are a new feature added to discord in the brand new 2.0.0a update. Read more about it here(in the discord.py server)

image

How can I install discord.py v2?

It's pretty simple all you have to do it go to your console/terminal and say the following:

pip install -U git+https://github.com/Rapptz/discord.py

Note: You need to have Git BASH and a python version higher than or equal to 3.8.0. Get it at python.org/downloads

Now let's get started shall we? First of let me show you the bad way to make buttons

@client.command(brief="Send a message with a button!") # Create a command inside a cog
async def button(self, ctx):
    view = discord.ui.View() # Establish an instance of the discord.ui.View class
    style = discord.ButtonStyle.gray  # The button will be gray in color
    item = discord.ui.Button(style=style, label="Read the docs!", url="https://discordpy.readthedocs.io/en/master")  # Create an item to pass into the view class.
    view.add_item(item=item)  # Add that item into the view class
    await ctx.send("This message has buttons!", view=view)  # Send your message with a button.

This example is shown when you say ?tag button example in any channel in the official dpy server but this is wrong! Why? you may ask Reason: It's because the button style doesn't work perfectly and all butttons are url buttons.

So what's the good/better way to make buttons? I never said the method provided above was wrong but it just isn't feasible of sorts. But, the better way is to sub-class the buttons isn't a view class(discord.ui.View) like follows: Code:

import discord
from discord.ext import commands 

client=commands.Bot(command_prefix=".")

class Buttons(discord.ui.View):
    def __init__(self, *, timeout=180):
        super().__init__(timeout=timeout)
    @discord.ui.button(label="Button",style=discord.ButtonStyle.gray)
    async def gray_button(self,button:discord.ui.Button,interaction:discord.Interaction):
        await interaction.response.edit_message(content=f"This is an edited button response!")

@client.command()
async def button(ctx):
    await ctx.send("This message has buttons!",view=Buttons())

token=""
client.run(token)

Response:

image

Response - On Click:

image

Let me explain what happened just happened. First we delared the bot(client=commands.Bot()), then we made a class called Buttons() and it was a simple view(discord.ui.View) class Then we declared the view as self, and timeout as 180 seconds in the def __init__(): right after that we added the timeout to the view in the super().__init__() Right after we added an @discord.ui.button decorator which declares a button and in the decorator we declared the label and style a lot more things can be declared in there which will be shown later on in the gist. Then we called our button as gray_button inside an asynchronous function(basically the button's asynchronous callback function) and inside that we declared our:

(a) view as self (b) discord.ui.Button as button (c) discord.Interaction as interaction

Right after that we opened up the funtion and added in a await interaction.response.edit_message() and added some content to it. After that we delcared a command(button), added one argument to it(ctx) and sent a primary/base message with the content as "This message has buttons!", and, then added in the view class we defined earlier(Button()) as view=Buttons() Then ran the bot

Now that I gave you the a small summary of what just happened in the above code, let me tell you the various attributes of the @discord.ui.button decorator. Taken from the API. Reference Link: ui.Button

image

Basic Required Attributes:

  1. label

This is the button's label, basically what's shown when the message is sent.

  1. style

This is the button's style, basically what the button looks like when the message is sent. Various Styles: image Again taken from the API

image How can I change the button style?

In your @discord.ui.button decorator add in a style parameter and do something like below

image

How do I change the button style on click?

That's actually a better question that pops up in someone's head because they've seen buttons change styles on click and let me tell you it's pretty easy to do. Take an example of the code below.

Code:

# Note: This is just an "improved" code of what's shown above and that's how it's going to work throughout the gist the above code is going to be refined over and over again.
import discord
from discord.ext import commands 

client=commands.Bot(command_prefix=".")

class Buttons(discord.ui.View):
    def __init__(self, *, timeout=180):
        super().__init__(timeout=timeout)
    @discord.ui.button(label="Button",style=discord.ButtonStyle.gray)
    async def blurple_button(self,button:discord.ui.Button,interaction:discord.Interaction):
        button.style=discord.ButtonStyle.green
        await interaction.response.edit_message(content=f"This is an edited button response!",view=self)

@client.command()
async def button(ctx):
    await ctx.send("This message has buttons!",view=Buttons())
    
token=""
client.run(token)

Initial Response:

image

Response - On Click:

image

When changing anything in your button all you have to do is add in a view=self in your interaction.response.edit_message() But, if you'd like to change the style on the click on a interaction.response.send_message(), the following would be your output with the above shown code, but, with the await interaction.response.edit_message(...,view=self), replaced, with await interaction.response.send_message(...,ephemeral=False) you may make it True if you'd like too

Response(s):

image

That would be your response and if you had ephemeral as True then all responses would only be able to be seen by the button clicker and not the command user. If you'd like to add an interaction_check funtion, and send a message when the interaction user isn't the command user it's shown below or futher in the gist(don't fret!)

Let's get back to the main topic - components of a button

  1. emoji

This is basically the emoji that pops up on the left-side of the button. So, how can I use these emojis? You may use the emojis in the below format. To get this "format" just add a \ before the emoji name regardless if it's a discord default, unicode, or, discord custom(statis or animated) and the emoji ID is what's going to pop up as: (a) <:[emoji_name]:[emoji_id]> for a static emoji (b) <a:[emoji_name]:[emoji_id]> for an animated emoji

For getting the unicode character(s) of the entered text(as shown in the below picture) go to the discord.py server and say ?charinfo <chracter(s)> and the bot'll respond with the related information

image

Code:

import discord
from discord.ext import commands

client=commands.Bot(command_prefix=".")

class Buttons(discord.ui.View):
    def __init__(self, *, timeout=180):
        super().__init__(timeout=timeout)
    @discord.ui.button(label="Blurple Button",style=discord.ButtonStyle.blurple,emoji="🎁") # or .primary
    async def blurple_button(self,button:discord.ui.Button,interaction:discord.Interaction):
        button.disabled=True
        await interaction.response.edit_message(view=self)
    @discord.ui.button(label="Gray Button",style=discord.ButtonStyle.gray,emoji="\U0001f974") # or .secondary/.grey
    async def gray_button(self,button:discord.ui.Button,interaction:discord.Interaction):
        button.disabled=True
        await interaction.response.edit_message(view=self)
    @discord.ui.button(label="Green Button",style=discord.ButtonStyle.green,emoji="<:FD_pepeyay:878854266012438549>") # or .success
    async def green_button(self,button:discord.ui.Button,interaction:discord.Interaction):
        button.disabled=True
        await interaction.response.edit_message(view=self)
    @discord.ui.button(label="Red Button",style=discord.ButtonStyle.red,emoji="<a:PomRun:869781523971317811>") # or .danger
    async def red_button(self,button:discord.ui.Button,interaction:discord.Interaction):
        button.disabled=True
        await interaction.response.edit_message(view=self)

@client.command()
async def button(ctx):
    view=Buttons()
    view.add_item(discord.ui.Button(label="URL Button",style=discord.ButtonStyle.link,url="https://github.com/lykn",emoji="<a:kannaWink:909791444661850132>"))
    await ctx.send("This message has buttons!",view=view)

token=""
client.run(token)

Response:

image

Those were the basic componenets that are required to make a good button. Below I'm going to show you the code and response to the code where all the button styles are shown

Code:

# Note: In the below code the buttons get disabled on click.
""" Note: The last button is a URL button which takes in a `url` param and has to be added via declaring the view in a variable and then adding a the item in the view through the variable """

import discord
from discord.ext import commands

client=commands.Bot(command_prefix=".")

class Buttons(discord.ui.View):
    def __init__(self, *, timeout=180):
        super().__init__(timeout=timeout)
    @discord.ui.button(label="Blurple Button",style=discord.ButtonStyle.blurple) # or .primary
    async def blurple_button(self,button:discord.ui.Button,interaction:discord.Interaction):
        button.disabled=True
        await interaction.response.edit_message(view=self)
    @discord.ui.button(label="Gray Button",style=discord.ButtonStyle.gray) # or .secondary/.grey
    async def gray_button(self,button:discord.ui.Button,interaction:discord.Interaction):
        button.disabled=True
        await interaction.response.edit_message(view=self)
    @discord.ui.button(label="Green Button",style=discord.ButtonStyle.green) # or .success
    async def green_button(self,button:discord.ui.Button,interaction:discord.Interaction):
        button.disabled=True
        await interaction.response.edit_message(view=self)
    @discord.ui.button(label="Red Button",style=discord.ButtonStyle.red) # or .danger
    async def red_button(self,button:discord.ui.Button,interaction:discord.Interaction):
        button.disabled=True
        await interaction.response.edit_message(view=self)

@client.command()
async def button(ctx):
    view=Buttons()
    view.add_item(discord.ui.Button(label="URL Button",style=discord.ButtonStyle.link,url="https://github.com/lykn"))
    await ctx.send("This message has buttons!",view=view)

token=""
client.run(token)

Response:

Dark Mode

image

Light Mode

image

Heads Up!

URL Buttons can't be added into the button's class, aka, a button's callback funtion in a class, but, to have such a button you need to make a discord.ui.View class(a simple view class) and then name you variable in your command, let's call this variable v. The, you have to do something like what's shown below

@client.command()
async def button(ctx):
    v=Buttons()
    v.add_item(discord.ui.Button(label="URL Button",style=discord.ButtonStyle.link,url="https://github.com/lykn"))
    await ctx.send("This message has buttons!",view=v)

Functions Inside Button Callback

All the parameters that can be added inside the @discord.ui.Button decorator can be passed in an individual button's callback by declaring the discord.ui.Button as a positinal arguement your async def button_name(self,_____:discord.ui.Button) function(button callback)

Let's make a code where on the click of a button all the other buttons get disabled! Note: This is just a smol code to show you how to use for loops inside a button's callback Code: We are going to be for looping a "child" in self.children(i.e, the button's view components)

import discord
from discord.ext import commands
from discord.ui import view 

client=commands.Bot(command_prefix=".")

class Buttons(discord.ui.View):
    def __init__(self, *, timeout=180):
        super().__init__(timeout=timeout)
    @discord.ui.button(label="Blurple Button",style=discord.ButtonStyle.blurple) # or .primary
    async def blurple_button(self,button:discord.ui.Button,interaction:discord.Interaction):
        button.disabled=True
        await interaction.response.edit_message(view=self)
    @discord.ui.button(label="Gray Button",style=discord.ButtonStyle.gray) # or .secondary/.grey
    async def gray_button(self,button:discord.ui.Button,interaction:discord.Interaction):
        button.disabled=True
        await interaction.response.edit_message(view=self)
    @discord.ui.button(label="Green Button",style=discord.ButtonStyle.green) # or .success
    async def green_button(self,button:discord.ui.Button,interaction:discord.Interaction):
        button.disabled=True
        await interaction.response.edit_message(view=self)
    @discord.ui.button(label="Red Button",style=discord.ButtonStyle.red) # or .danger
    async def red_button(self,button:discord.ui.Button,interaction:discord.Interaction):
        button.disabled=True
        await interaction.response.edit_message(view=self)
    @discord.ui.button(label="Change All",style=discord.ButtonStyle.success)
    async def color_changing_button(self,child:discord.ui.Button,interaction:discord.Interaction):
        for child in self.children:
            child.disabled=True
        await interaction.response.edit_message(view=self)
            
@client.command()
async def button(ctx):
    view=Buttons()
    view.add_item(discord.ui.Button(label="URL Button",style=discord.ButtonStyle.link,url="https://github.com/lykn"))
    await ctx.send("This message has buttons!",view=view)

token=""
client.run(token)

Response:

image

Required Button:

image

Response - On Click:

image

And as all good things come to an end, I have come to the last few lines of this gist. Firstly I'd like to thank everyone at the discord.py server who have helped me figure out how to make buttons on the whole you guys are amazing(Includes Umbra#9999 if he reads this, that is😆)! A special thanks goes to LeoCx1000#9999, veyron#1741,Jeyy#6639, Hay#7860, Ender2K89#9999, SHERLOCK#7309 and Nyanaka#1224 for helping me with all the patience in this world!

Thanks to everyone reading this! If you feel something is wrong/needs correction or just need some help then drop a comment down below

This is Lykn signing off.

@adieltan
Copy link

adieltan commented Dec 8, 2021

nice gist

@infinotiver
Copy link

ERROR AttributeError: module 'discord' has no attribute 'ui'

@MaskDuck
Copy link

MaskDuck commented Dec 12, 2021

@prakarsh17
Please make sure you have discord.py v2.0.0 (not v1.7.3, the version on PyPi is version 1.7.3)
If you want to know how to install v2.0, see this message in server discord.py.
If you are using replit, see this message (again, in discord.py) server.
Let the community know if you have question! The discord.py community always glad to help you!

@LeoCx1000
Copy link

LeoCx1000 commented Dec 12, 2021

Noice 👍 💯
Although I would suggest naming your commands.Bot variable bot not client just for detailing, and to be less misleading 👍

Also, maybe put a line break between each discord.ui.button decorator and callback to look nicer.

@lykn
Copy link
Author

lykn commented Dec 12, 2021

First off I'd like to thank @MaskDuck for helping you out, secondly can you show me your code if its not a biggie @prakarsh17?
Usually its mostly just an importing error but there isn't any need for importing anything, but, still the import would be, from discord import ui.
If you copy pasted my code and tried to make things work it would if you read everything word-to-word, but, if it still showed this then there is some sort of version control issue(check your discord.py version by printing discord.__version__[Example: print(discord.__version__)])
If you still have any issues after reading this semi-gist of a comment then join the discord.py official discord server as MaskDuck has said, and, everyone here will you.

  • Lykn

@infinotiver
Copy link

Oh let me try again i usually use pip so thats why I may have missed it
btw @MaskDuck thanks to you too you helped me change my discord.py's version which I too wanted .
@lykn it is not working just sends the message this message has buttons . Just that
image

@MaskDuck
Copy link

MaskDuck commented Dec 15, 2021

@prakarsh17 When you online, could you ping me in the testing channel of the server discord.py (MaskDuck#0694) and I will help you more!

@lykn
Copy link
Author

lykn commented Dec 16, 2021

@prakarsh17 please DM Lykn#1669(ID: 779347811099475978) and I'll help you out!

@TheOnlyWayUp
Copy link

Ty, pretty useful :)

@ASH1226
Copy link

ASH1226 commented Mar 24, 2022

Thanks, it helped me alot.

Copy link

ghost commented Apr 6, 2022

Thanks :)

@JustinLiAtSBU
Copy link

Does anybody know how to access class variables in the button decorator? For example in my code:
@discord.ui.button(label=f"{self.members} members", style=discord.ButtonStyle.danger)

I get an error: NameError: name 'self' is not defined

@TheDarkKnight69
Copy link

+1
gist is nice ty for that

@bcc1312
Copy link

bcc1312 commented Apr 20, 2022

@prakarsh17 please DM Lykn#1669(ID: 779347811099475978) and I'll help you out!

i cannot find you and i have aquestion

@beackers
Copy link

I is a random scrolling through public gists doing a little trolling 😛

bruh if you want to troll then go do it somewhere else

@Navneety007
Copy link

I'd highly recommend creating a button class as well since all of the buttons are functioning the same, and it'd create the code short and clean as well..........well written btw

@Navneety007
Copy link

Does anybody know how to access class variables in the button decorator? For example in my code: @discord.ui.button(label=f"{self.members} members", style=discord.ButtonStyle.danger)

I get an error: NameError: name 'self' is not defined

@JustinLiAtSBU You can't use self in the decorator of the class
So I'd suggest ya to give a custom ID to the button and in the class init alter the button label and you can then mention the class variables.

That would be the only possible way in my perspective, hope it helps.

@hypogirl
Copy link

i'm getting a strange error
print(interaction.response) AttributeError: 'Button' object has no attribute 'response'
in a class very similar to the Button classes you showed. interaction is obviously supposed to be a discord interaction but for some reason it's being interpreted as a button itself(?)

@developmentPluto
Copy link

I am getting the same error

@LeoCx1000
Copy link

LeoCx1000 commented May 31, 2022

@slocknad @developmentPluto

as shown in the official examples and docs, the button parameter is the second one not the first one anymore.

For future reference, I would suggest using those resources instead, as they'll always be up-to-date with any breaking changes in the library👍

Breaking changes are also always announced in the #updates channel of the official discord server every monday.

class ExampleView(discord.ui.View):
    @discord.ui.button(...)
    async def my_button(self, interaction: discord.Interaction, button: discord.ui.Button):
        ... #                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^
        
    @discord.ui.select(...)
    async def my_select(self, interaction: discord.Interaction, select: discord.ui.Select):
        ... #                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^

@lgoette
Copy link

lgoette commented Jun 27, 2022

I just wasted 2 hours to recognize this. I wish i found this comment earlier. xD

@HeyItsJustFelix
Copy link

Thank you so much for this!

@Stirven13
Copy link

Best!

@kub1ce
Copy link

kub1ce commented Oct 22, 2022

Hey, if in the first example you do not specify the "url" parameter, the button will be normal, and not with a link
@lykn (sorry by mention :з)

@jaylac2000
Copy link

very helpful!

@nebeluga
Copy link

image
Help

@SkyShadowHero
Copy link

great!So helpful!!!

@p-m986
Copy link

p-m986 commented Jan 14, 2024

This Gist is outdated... Please refer to the new documentations

@kem008
Copy link

kem008 commented Jan 24, 2024

this is not working.

@fish0117
Copy link

Thanks! Very useful:)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment