A small helper class for discord.py that builds a discord.ui.LayoutView straight from a raw
Components V2 payload (the plain dict/JSON shape Discord itself sends and expects), and converts
it back.
Normally you build a LayoutView by instantiating the discord.ui items yourself
(discord.ui.Container(...), discord.ui.Section(...), etc) and adding them to the view with
add_item. That's fine when you're writing the layout by hand, but it gets annoying if you want
to store layouts somewhere (a database, a JSON file, a layout editor) and load them dynamically.
This handler bridges that gap: give it the dict, get back a real view.
Useful if you're building something like a no-code embed/layout builder, saving user-made layouts to a database, or just want to round-trip a layout you received back into something editable.
On init, it builds two lookup tables keyed by Discord's component type IDs:
- one mapping each type ID to the private method that knows how to build that specific
discord.uiitem - one just for selects, since types 3 and 5-8 are all "select menus" but map to different classes
(
Select,UserSelect,RoleSelect,MentionableSelect,ChannelSelect)
from_dict walks the list of component dicts and adds whatever gets built to a LayoutView.
Containers, sections, and action rows all have their own nested components list, so those
methods recurse back into the same lookup table to build their children.
to_dict is just a thin wrapper around view.to_components(), which discord.py already gives
you. It's mostly there so you have one object with both directions on it.
| ID | Component |
|---|---|
| 1 | Action Row |
| 2 | Button |
| 3 | Select (string select) |
| 5 | User Select |
| 6 | Role Select |
| 7 | Mentionable Select |
| 8 | Channel Select |
| 9 | Section |
| 10 | Text Display |
| 11 | Thumbnail |
| 12 | Media Gallery |
| 13 | File |
| 14 | Separator |
| 17 | Container |
Say you've got this payload — a container with some text, a section with a thumbnail accessory, and an action row with a user select:
data = [
{
"type": 17, # Container
"accent_color": 0x00FF00,
"spoiler": False,
"components": [
{"type": 10, "content": "Hello world"},
{
"type": 9, # Section
"components": [{"type": 10, "content": "Section text"}],
"accessory": {
"type": 11, # Thumbnail
"media": {"url": "https://example.com/img.png"},
"description": "alt text",
"spoiler": False,
},
},
{
"type": 1, # Action Row
"components": [
{
"type": 5, # User Select
"custom_id": "usersel",
"placeholder": "Pick a user",
}
],
},
],
}
]Turning that into an actual view is just:
handler = DictLayoutViewHandler(data)
view = handler.from_dict(data)
await channel.send(view=view)And getting the dict back out again:
raw = handler.to_dict(view)which gives you back the same structure, just normalized (defaults filled in, keys reordered, etc):
[
{
"type": 17,
"accent_color": 65280,
"spoiler": False,
"components": [
{"type": 10, "content": "Hello world"},
{
"type": 9,
"components": [{"type": 10, "content": "Section text"}],
"accessory": {
"type": 11,
"spoiler": False,
"media": {"url": "https://example.com/img.png"},
"description": "alt text",
},
},
{
"type": 1,
"components": [
{
"type": 5,
"custom_id": "usersel",
"min_values": 1,
"max_values": 1,
"disabled": False,
"required": True,
"placeholder": "Pick a user",
}
],
},
],
}
]