SkillAgentSearch skills...

Reactionmenu

A library to create a discord.py 2.0+ paginator (reaction menu/buttons menu). Supports pagination with buttons, reactions, and category selection using selects.

Install / Use

/learn @Defxult/Reactionmenu

README

logo

<div align="center">

Downloads Downloads Downloads

python_version

</div>

How to install

You can install the latest PyPI version of the library by doing:

$ pip install reactionmenu

Or the development version:

$ pip install git+https://github.com/Defxult/reactionmenu

Intents

Minimum intents needed

bot = commands.Bot(..., intents=discord.Intents(messages=True, guilds=True, reactions=True, members=True))

ReactionMenu

class reactionmenu.ReactionMenu(method: Union[Context, discord.Interaction], /, *, menu_type: MenuType, **kwargs)

A ReactionMenu is a menu that uses emojis which are either custom guild emojis or a normal emoji to control the pagination process. If you're not looking for any of the fancy features and just want something simple, this is the one to use.

showcase

<details> <summary><b>Click to show ReactionMenu documentation</b></summary>

How to import

from reactionmenu import ReactionMenu, ReactionButton

This library comes with several methods and options in order to make a discord reaction menu simple. Once you have imported the proper classes, you will initialize the constructor like so:

menu = ReactionMenu(method, menu_type=ReactionMenu.TypeEmbed)

Parameters of the ReactionMenu constructor

  • method (Union[discord.ext.commands.Context, discord.Interaction]) A context or interaction object
  • menu_type (MenuType) The configuration of the menu
    • ReactionMenu.TypeEmbed, a normal embed pagination menu
    • ReactionMenu.TypeEmbedDynamic, an embed pagination menu with dynamic data
    • ReactionMenu.TypeText, a text only pagination menu

Kwargs of the ReactionMenu constructor

| Name | Type | Default Value | Used for | Info -------|------|---------------|----------|------ | wrap_in_codeblock | str | None | ReactionMenu.TypeEmbedDynamic | The discord codeblock language identifier to wrap your data in. Example: ReactionMenu(ctx, ..., wrap_in_codeblock='py') | custom_embed | discord.Embed | None | ReactionMenu.TypeEmbedDynamic | Embed object to use when adding data with ReactionMenu.add_row(). Used for styling purposes | delete_on_timeout | bool | False | All menu types | Delete the menu when it times out | clear_reactions_after | bool | True | All menu types | delete all reactions after the menu times out | navigation_speed | str | ReactionMenu.NORMAL | All menu types | Sets if the user needs to wait for the reaction to be removed by the bot before "turning" the page. Setting the speed to ReactionMenu.FAST makes it so that there is no need to wait (reactions are not removed on each press) and can navigate lengthy menu's more quickly | only_roles | List[discord.Role] | None | All menu types | If set, only members with any of the given roles are allowed to control the menu. The menu owner can always control the menu | timeout | Union[int, float, None] | 60.0 | All menu types | The timer for when the menu times out. Can be None for no timeout | show_page_director | bool | True | All menu types | Shown at the bottom of each embed page. "Page 1/20" | name | str | None | All menu types | A name you can set for the menu | style | str | "Page $/&" | All menu types | A custom page director style you can select. "$" represents the current page, "&" represents the total amount of pages. Example: ReactionMenu(ctx, ..., style='On $ out of &') | all_can_click | bool | False | All menu types | Sets if everyone is allowed to control when pages are 'turned' when buttons are clicked | delete_interactions | bool | True | All menu types | Delete the prompt message by the bot and response message by the user when asked what page they would like to go to when using ReactionButton.Type.GO_TO_PAGE | rows_requested | int | None | ReactionMenu.TypeEmbedDynamic | The amount of information per ReactionMenu.add_row() you would like applied to each embed page | remove_extra_emojis | bool | False | All menu types | If True, all emojis (reactions) added to the menu message that were not originally added to the menu will be removed

Pages for ReactionMenu

Depending on the menu_type, pages can either be a str, discord.Embed, or a combination of content and files (example below)

  • If the menu_type is ReactionMenu.TypeEmbed, use embeds
  • If the menu_type is ReactionMenu.TypeText (text only menu) or ReactionMenu.TypeEmbedDynamic (embed only menu), use strings.
  • Associated methods
    • ReactionMenu.add_page(embed: discord.Embed=MISSING, content: Optional[str]=None, files: Optional[Sequence[discord.File]]=None)
    • ReactionMenu.add_pages(pages: Sequence[Union[discord.Embed, str]])
    • ReactionMenu.add_row(data: str)
    • ReactionMenu.remove_all_pages()
    • ReactionMenu.clear_all_row_data()
    • ReactionMenu.remove_page(page_number: int)
    • ReactionMenu.set_main_pages(*embeds: Embed)
    • ReactionMenu.set_last_pages(*embeds: Embed)

Adding Pages

# ReactionMenu.TypeEmbed
menu = ReactionMenu(method, menu_type=ReactionMenu.TypeEmbed)
menu.add_page(summer_embed)
menu.add_page(winter_embed)

# ReactionMenu.TypeText
menu = ReactionMenu(method, menu_type=ReactionMenu.TypeText)
menu.add_page(content='Its so hot!')
menu.add_page(content='Its so cold!')

ReactionMenu.TypeText

A TypeText menu is a text based pagination menu. No embeds are involved in the pagination process, only plain text is used.

showcase-text

Stacked Pages

With v3.1.0+, you can paginate with more than just an embed or text. You can combine text, embeds, as well as files. But depending on the menu_type the combination can be restricted. Here is an example of a menu with a menu_type of TypeEmbed that is stacked.

# You can use regular commands as well
@bot.tree.command(description="These are stacked pages", guild=discord.Object(id=...))
async def stacked(interaction: discord.Interaction):
    menu = ReactionMenu(interaction, menu_type=ReactionMenu.TypeEmbed)

    menu.add_page(discord.Embed(title="My Embed"), content="This content is stacked on top of a file", files=[discord.File("stacked.py")])
    menu.add_page(discord.Embed(title="Hey Wumpos, can you say hi to the person reading this? 😃"))
    menu.add_page(discord.Embed(title="Hi, I'm Wumpos!"), files=[discord.File("wumpos.gif")])
    
    menu.add_button(ReactionButton.back())
    menu.add_button(ReactionButton.next())
    
    await menu.start()

stacked

Since the menu_type is TypeEmbed, there always has to be an embed on each page. If the menu_type was TypeText, embeds aren't allowed and you will be restricted to only using the files parameter.

ReactionMenu.TypeEmbedDynamic

A dynamic menu is used when you do not know how much information will be applied to the menu. For example, if you were to request information from a database, that information can always change. You query something and you might get 1,500 results back, and the next maybe only 800. A dynamic menu pieces all this information together for you and adds it to an embed page by rows of data. ReactionMenu.add_row() is best used in some sort of Iterable where everything can be looped through, but only add the amount of data you want to the menu page.

NOTE: In a dynamic menu, all added data is placed in the description section of an embed. If you choose to use a custom_embed, all text in the description will be overridden with the data you add

  • Associated methods
    • ReactionMenu.add_row(data: str)
    • ReactionMenu.clear_all_row_data()
    • ReactionMenu.set_main_pages(*embeds: Embed)
    • ReactionMenu.set_last_pages(*embeds: Embed)
  • The kwargs specifically made for a dynamic menu are:
    • rows_requested - The amount of rows you would like on each embed page before making a new page
      • ReactionMenu(..., rows_requested=5)
    • custom_embed - An embed you have created to use as the embed pages. Used for your menu aesthetic
      • ReactionMenu(..., custom_embed=red_embed)
    • wrap_in_codeblock - The language identifier when wrapping your data in a discord codeblock.
      • ReactionMenu(..., wrap_in_codeblock='py')
Adding Rows/data
menu = ReactionMenu(ctx, menu_type=ReactionMenu.TypeEmbedDynamic, rows_requested=5)

for data in database.request('SELECT * FROM customers'):
    menu.add_row(data)
Deleting Data

You can remove all the data you've added to a menu by using menu.clear_all_row_data()

Main/Last Pages

When using a dynamic menu, the only embed pages you see are from the data you've added. But if you would like to show more pages other than just the data, you can use methods ReactionMenu.set_main_pages() and ReactionMenu.set_last_pages(). Setting the main page(s), the embeds you set will be the first embeds that are shown when the menu starts. Setting the last page(s) are the last embeds shown

menu.set_main_pages(welcome_embed, announcement_embed)

for data in get_information():
    menu.add_row(data)

menu.set_last_pages(additional_info_embed)
# NOTE: setting main/last pages can be set in any order

ReactionButto

Related Skills

View on GitHub
GitHub Stars119
CategoryCustomer
Updated1mo ago
Forks12

Languages

Python

Security Score

100/100

Audited on Feb 21, 2026

No findings