Skip to main content

DiscordPYComponents

Discord Components V2 for discord.py — a lightweight helper library for building rich, interactive messages with the modern Components V2 system.

Requires the IS_COMPONENTS_V2 flag (1 << 15).
When this flag is set, traditional content and embeds are disabled; all content must be sent as components.

PyPI: https://pypi.org/project/DiscordPYComponents/

Official Discord docs:

Installation

pip install DiscordPYComponents

Requirements

  • Python 3.10+
  • discord.py (or any library that gives you a bot token + channel/interaction)
  • aiohttp

Quick start

from py_components import (
    UI, TextDisplay, Button, ButtonStyle, Container, Separator, Section, Thumbnail
)

@bot.command()
async def menu(ctx):
    ui = UI(
        TextDisplay("# Welcome"),
        TextDisplay("Choose an option below:"),
        Button("Confirm", custom_id="confirm", style=ButtonStyle.SUCCESS),
        Button("Cancel", custom_id="cancel", style=ButtonStyle.DANGER),
    )
    await ui.send(ctx)

Component types

Content components

Class Type Description
TextDisplay / Text 10 Markdown text (1–4000 chars)
Thumbnail 11 Small image (Section accessory only)
MediaGallery 12 1–10 images / media items
File 13 Displays an uploaded attachment

Layout components

Class Type Description
ActionRow 1 Holds up to 5 Buttons or one Select menu
Section 9 1–3 TextDisplays + optional accessory (Button or Thumbnail)
Separator 14 Vertical padding / visual divider
Container 17 Groups children with optional accent colour bar

Interactive components

Class Type Description
Button 2 Clickable button
StringSelect 3 Dropdown of string options
UserSelect 5 Select users
RoleSelect 6 Select roles
MentionableSelect 7 Select users or roles
ChannelSelect 8 Select channels

Button styles

Style Value Colour / behaviour
ButtonStyle.PRIMARY 1 Blurple
ButtonStyle.SECONDARY 2 Grey
ButtonStyle.SUCCESS 3 Green
ButtonStyle.DANGER 4 Red
ButtonStyle.LINK 5 Grey – opens a URL (requires url=)
ButtonStyle.PREMIUM 6 Blurple – requires sku_id=
Button("Click me", custom_id="btn1", style=ButtonStyle.PRIMARY)
Button("Docs", style=ButtonStyle.LINK, url="https://discord.com/developers/docs")
Button("Buy", style=ButtonStyle.PREMIUM, sku_id="1234567890")

Building a rich layout

from py_components import (
    UI, Container, TextDisplay, Section, Thumbnail,
    Separator, SeparatorSpacing, MediaGallery, Button, ButtonStyle
)

ui = UI(
    Container(
        TextDisplay("# Server Status"),
        Separator(divider=True, spacing=SeparatorSpacing.SMALL),
        Section(
            TextDisplay("**Online** — 1 204 members"),
            TextDisplay("Peak today: 312"),
            accessory=Thumbnail("https://cdn.discordapp.com/icons/.../icon.png"),
        ),
        Separator(),
        MediaGallery(
            "https://example.com/chart1.png",
            "https://example.com/chart2.png",
        ),
        accent_color=0x5865F2,   # Discord blurple
    ),
    Button("Refresh", custom_id="refresh", style=ButtonStyle.PRIMARY),
)
await ui.send(ctx)

Top-level components can be mixed freely. The UI class automatically wraps loose Buttons into ActionRows (max 5 per row). Place select menus inside an explicit ActionRow yourself:

from py_components import ActionRow, StringSelect, SelectOption

ui = UI(
    TextDisplay("Pick a colour:"),
    ActionRow(
        StringSelect(
            custom_id="colour",
            options=[
                SelectOption("Red", "red"),
                SelectOption("Green", "green"),
                SelectOption("Blue", "blue"),
            ],
            placeholder="Choose…",
        )
    ),
)

View & callbacks

from py_components import View, ButtonStyle

view = View()

async def on_confirm(interaction):
    await interaction.response.send_message("Confirmed!", ephemeral=True)

view.add_button("Confirm", custom_id="confirm", style=ButtonStyle.SUCCESS, callback=on_confirm)
view.add_button("Cancel", custom_id="cancel", style=ButtonStyle.SECONDARY)

# Send the payload yourself or combine with UI
payload = view.to_payload()

You can also use the decorator helper:

from py_components import button, View

@button("Click Me", custom_id="my_btn")
async def on_click(interaction):
    await interaction.response.send_message("Clicked!")

Global registry

from py_components import default_registry

@default_registry.route("confirm")
async def handle_confirm(interaction):
    await interaction.response.send_message("OK")

# Later, in your interaction listener:
await default_registry.dispatch(interaction.data["custom_id"], interaction)

File attachments

Upload the file with the message and reference it with the File component:

from py_components import UI, File, TextDisplay

ui = UI(
    TextDisplay("Here is the report:"),
    File("report.pdf"),          # becomes attachment://report.pdf
)

# When calling the raw HTTP helper you would also pass the file bytes;
# with discord.py you can combine the payload with files=...
await ui.send(ctx)

Responding to interactions

@bot.event
async def on_interaction(interaction):
    if interaction.type.name == "component":
        custom_id = interaction.data.get("custom_id")
        # … route to your callbacks …
        # or reply with a new V2 message:
        ui = UI(TextDisplay(f"You pressed `{custom_id}`"))
        await ui.reply(interaction, ephemeral=True)

Payload shape

Every payload produced by this library looks like:

{
  "flags": 32768,
  "components": [
    { "type": 10, "content": "Hello" },
    {
      "type": 1,
      "components": [
        { "type": 2, "style": 1, "label": "OK", "custom_id": "ok" }
      ]
    }
  ]
}

You can also obtain the dict with ui.to_payload() / view.to_payload() and send it through any HTTP client or discord.py’s low-level methods.

Limitations (Discord-side)

  • Once a message is sent with IS_COMPONENTS_V2 the flag cannot be removed.
  • content, embeds, stickers and poll are disabled on V2 messages.
  • Attachments only appear when referenced by a File or media component.
  • Max 40 components per message.
  • Buttons must live in an ActionRow (or as a Section accessory).
  • Only one select menu per ActionRow.

License

MIT

Metadata

Release files for DiscordPYComponents 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for DiscordPYComponents 1.0.0
File Size Uploaded
discordpycomponents-1.0.0.tar.gz 10.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for DiscordPYComponents 1.0.0
File Interpreter ABI Platform
discordpycomponents-1.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 23.6 kB

Release files / discordpycomponents-1.0.0.tar.gz

Download URL discordpycomponents-1.0.0.tar.gz
Size 10.9 kB
Tags Source
SHA-256 checksum
How to use checksums
c9b6f9b0b885ad2c39fb7f00d3782fc6bec4d93c55e09523e56c750e6b9d0851
BLAKE2b-256 checksum
How to use checksums
c798488e061c8dbdb6f5aa65bb30b03bfa9cb5a21a310e8addd0ad247c84e01d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 18, 2026.

Transparency log

Release files / discordpycomponents-1.0.0-py3-none-any.whl

Download URL discordpycomponents-1.0.0-py3-none-any.whl
Size 12.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
878fe0c2d8766ba30823fe747a75cf42f2b81d13a4f35573f20fa899dc399193
BLAKE2b-256 checksum
How to use checksums
1b0d02eac9c6b90459854184ac67c5dafbdd4f4363dc22a82b7a59c127963e96
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 18, 2026.

Transparency log

Release history Release notifications | RSS feed

1.3.2

2 release files

1.3.1

2 release files

1.3.0

2 release files

This release

1.0.0 This release

2 release files

0.2.33

2 release files

0.2.31

2 release files

0.2.23

2 release files

0.2.11

2 release files

0.2.3

2 release files

0.2.2

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page