A fluent builder pattern for creating Discord UI LayoutViews with containers.
Project description
dpy-layout-builder
A fluent builder pattern for creating Discord UI LayoutViews with containers in discord.py.
Stop wrestling with nested Container, ActionRow, Section, and TextDisplay calls - chain a few methods and .build().
Installation
pip install dpy-layout-builder
Quick Start
import discord
from dpy_layout_builder import LayoutViewBuilder
async def my_callback(interaction: discord.Interaction):
await interaction.response.send_message("Clicked!", ephemeral=True)
view = (
LayoutViewBuilder()
.set_accent_color(discord.Color.blurple())
.add_header("# Welcome!")
.add_separator()
.add_text("Thanks for checking out the server.")
.add_separator()
.add_button("Get Started", style=discord.ButtonStyle.primary, callback=my_callback)
.build()
)
await interaction.response.send_message(view=view)
Features
| Method | Description |
|---|---|
.set_accent_color(color) |
Set the container accent color |
.set_spoiler(True) |
Mark the container as a spoiler |
.add_header(text) |
Add a heading (use # markdown) |
.add_text(text) |
Add a text block |
.add_separator() |
Add a visual divider |
.add_section(text, ...) |
Add a section with optional thumbnail or button accessory |
.add_button(label, ...) |
Add a button (auto-grouped into ActionRows, max 5 per row) |
.add_select(placeholder, options, ...) |
Add a dropdown select menu |
.add_media_gallery(*urls) |
Add an image gallery (up to 10) |
.add_file(url, ...) |
Add a file display |
.add_raw_item(item) |
Escape hatch - add any discord.ui component |
.build(timeout=180) |
Build the final LayoutView |
Examples
Section with Thumbnail
view = (
LayoutViewBuilder()
.set_accent_color(discord.Color.green())
.add_header("# User Profile")
.add_separator()
.add_section(
"**Username:** Strasse\n**Level:** 42\n**Joined:** 2024",
thumbnail_url="https://example.com/avatar.png",
)
.build()
)
Section with Button Accessory
from dpy_layout_builder import LayoutViewBuilder, ButtonConfig
view = (
LayoutViewBuilder()
.add_section(
"Click the button to claim your reward!",
button=ButtonConfig(
label="Claim",
style=discord.ButtonStyle.success,
callback=claim_callback,
),
)
.build()
)
Multiple Buttons
view = (
LayoutViewBuilder()
.set_accent_color(discord.Color.red())
.add_text("Choose an action:")
.add_separator()
.add_button("Approve", style=discord.ButtonStyle.success, callback=approve)
.add_button("Deny", style=discord.ButtonStyle.danger, callback=deny)
.add_button("Skip", style=discord.ButtonStyle.secondary, callback=skip)
.build()
)
Select Menu
Using SelectOptionConfig for rich options with descriptions:
from dpy_layout_builder import LayoutViewBuilder, SelectOptionConfig
async def on_role_selected(interaction: discord.Interaction):
values = interaction.data.get("values", [])
selected = values[0] if values else None
await interaction.response.send_message(f"You picked: {selected}", ephemeral=True)
ROLE_OPTIONS = [
SelectOptionConfig(label="Announcements", value="announcements", description="Get pinged for announcements"),
SelectOptionConfig(label="Events", value="events", description="Get pinged for events"),
SelectOptionConfig(label="Giveaways", value="giveaways", description="Get pinged for giveaways"),
]
view = (
LayoutViewBuilder()
.add_text("Pick a notification role:")
.add_separator()
.add_select(
placeholder="Select a role...",
options=ROLE_OPTIONS,
callback=on_role_selected,
)
.build()
)
You can also pass plain strings for simple options:
view = (
LayoutViewBuilder()
.add_text("Pick your favorite color:")
.add_select("Choose a color...", ["Red", "Green", "Blue"], callback=on_color)
.build()
)
Multiple Containers
from dpy_layout_builder import LayoutViewBuilder, MultiContainerLayoutViewBuilder
view = (
MultiContainerLayoutViewBuilder()
.add_container(
LayoutViewBuilder()
.set_accent_color(discord.Color.red())
.add_header("# Warnings")
.add_text("You have 2 active warnings.")
)
.add_container(
LayoutViewBuilder()
.set_accent_color(discord.Color.green())
.add_header("# Rewards")
.add_text("You earned 500 XP today!")
)
.build()
)
Quick Helpers
from dpy_layout_builder import quick_info_view, quick_confirm_view
# Simple info display
info = quick_info_view(
"# Server Rules",
"1. Be respectful\n2. No spam\n3. Have fun!",
color=discord.Color.gold(),
footer="*Last updated: March 2026*",
)
# Confirmation dialog
confirm = quick_confirm_view(
"Are you sure you want to reset your progress?",
on_confirm=handle_confirm,
on_cancel=handle_cancel,
)
Build Safety
The builder is safe to call .build() multiple times - it snapshots internal state without mutating, so you can reuse a configured builder to produce multiple views.
Requirements
- Python 3.10+
- discord.py 2.7.1+ (with LayoutView / Components V2 support)
License
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file dpy_layout_builder-1.1.0.tar.gz.
File metadata
- Download URL: dpy_layout_builder-1.1.0.tar.gz
- Upload date:
- Size: 8.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6a49a5ed3d054aff10c2cb5d57107678102ad4bb821e00e65c6077037f27069e
|
|
| MD5 |
3748f4874c8fb98b240450cbafefa05c
|
|
| BLAKE2b-256 |
4ddc26a017cc84764dd6c49f5770b60ebf298d76e421e9da35943e7d881b5599
|
File details
Details for the file dpy_layout_builder-1.1.0-py3-none-any.whl.
File metadata
- Download URL: dpy_layout_builder-1.1.0-py3-none-any.whl
- Upload date:
- Size: 8.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c497737afd6ff22f2ce793a5150c21d9cf1dbbc17871efb1a3528af3da8b9db5
|
|
| MD5 |
9f351b94a21783e693104c68b1db5674
|
|
| BLAKE2b-256 |
50cabf8f0e3497a5ceadd12134223c6bc2f4e38d8ec65a5be916351928f2b586
|