| name | components-v2-layout |
| description | Guide for layout components (Container, Section, Separator) in Discord Components v2 Use when this capability is needed. |
| metadata | {"author":"erdemgksl"} |
Layout Components (Components v2)
What this skill does
Reference for creating message layouts using Container, Section, and Separator components.
When to use
- Structure complex messages with multiple elements
- Create horizontal layouts with text and buttons
- Add visual spacing and dividers
- Replace legacy embeds with modern Components v2
⚠️ IMPORTANT: IS_COMPONENTS_V2 Flag
All messages using these components must set the IS_COMPONENTS_V2 flag.
ctx.send(poise::CreateReply::default()
.flags(serenity::MessageFlags::IS_COMPONENTS_V2)
.components(components)
).await?;
Container (Type 17)
What is Container?
The primary wrapper for all Components v2 messages. Acts like a legacy embed but with more flexibility.
Creating Containers
Basic Container
use poise::serenity_prelude as serenity;
let inner_components = vec![
serenity::CreateContainerComponent::TextDisplay(
serenity::CreateTextDisplay::new("Hello World!")
),
];
let container = serenity::CreateContainer::new(inner_components);
vec![serenity::CreateComponent::Container(container)]
Container with Accent Color
serenity::CreateContainer::new(inner_components)
.accent_color(0x5865F2)
Building Container Components
let mut inner_components: Vec<serenity::CreateContainerComponent> = vec![];
inner_components.push(serenity::CreateContainerComponent::TextDisplay(
serenity::CreateTextDisplay::new("## Title")
));
inner_components.push(serenity::CreateContainerComponent::Separator(
serenity::CreateSeparator::new(false)
));
inner_components.push(serenity::CreateContainerComponent::Section(
serenity::CreateSection::new(
vec![serenity::CreateSectionComponent::TextDisplay(
serenity::CreateTextDisplay::new("Content")
)],
serenity::CreateSectionAccessory::Button(button)
)
));
let container = serenity::CreateContainer::new(inner_components);
Full Message Example
pub async fn send_message(ctx: Context<'_>) -> Result<(), Error> {
let mut inner_components = vec![];
inner_components.push(serenity::CreateContainerComponent::TextDisplay(
serenity::CreateTextDisplay::new("## Welcome!")
));
inner_components.push(serenity::CreateContainerComponent::Separator(
serenity::CreateSeparator::new(true)
));
let components = vec![
serenity::CreateComponent::Container(
serenity::CreateContainer::new(inner_components)
.accent_color(0x57F287)
)
];
ctx.send(poise::CreateReply::default()
.flags(serenity::MessageFlags::IS_COMPONENTS_V2)
.components(components)
).await?;
Ok(())
}
Section (Type 9)
What is Section?
Creates horizontal layouts with 1-3 text blocks on the left and an optional accessory (button/thumbnail) on the right.
Creating Sections
Section with Text and Button
serenity::CreateSection::new(
vec![
serenity::CreateSectionComponent::TextDisplay(
serenity::CreateTextDisplay::new("**Module Status**")
),
],
serenity::CreateSectionAccessory::Button(
serenity::CreateButton::new("toggle_module")
.label("Enable")
.style(serenity::ButtonStyle::Success)
),
)
Section with Multiple Text Blocks
serenity::CreateSection::new(
vec![
serenity::CreateSectionComponent::TextDisplay(
serenity::CreateTextDisplay::new("**Title**")
),
serenity::CreateSectionComponent::TextDisplay(
serenity::CreateTextDisplay::new("Description text")
),
serenity::CreateSectionComponent::TextDisplay(
serenity::CreateTextDisplay::new("*Additional info*")
),
],
serenity::CreateSectionAccessory::Button(button),
)
Section Accessories
Button Accessory
serenity::CreateSectionAccessory::Button(
serenity::CreateButton::new("action_id")
.label("Action")
.style(serenity::ButtonStyle::Primary)
)
Thumbnail Accessory (Not yet in codebase)
serenity::CreateSectionAccessory::Thumbnail(
serenity::CreateThumbnail::new("https://example.com/image.png")
)
Common Section Patterns
Settings Row
serenity::CreateContainerComponent::Section(
serenity::CreateSection::new(
vec![
serenity::CreateSectionComponent::TextDisplay(
serenity::CreateTextDisplay::new(format!(
"**{}**\n{}",
module_name,
description
))
),
],
serenity::CreateSectionAccessory::Button(
serenity::CreateButton::new(format!("config_module_toggle_{}", module_type))
.label(if enabled { "Enabled" } else { "Disabled" })
.style(if enabled {
serenity::ButtonStyle::Success
} else {
serenity::ButtonStyle::Danger
})
),
),
)
Header with Back Button
serenity::CreateContainerComponent::Section(
serenity::CreateSection::new(
vec![serenity::CreateSectionComponent::TextDisplay(
serenity::CreateTextDisplay::new(format!("## {}", title))
)],
serenity::CreateSectionAccessory::Button(
serenity::CreateButton::new(back_id)
.label("Back")
.style(serenity::ButtonStyle::Secondary)
),
),
)
Separator (Type 14)
What is Separator?
Adds visual spacing or dividers between components.
Creating Separators
Non-Spacing Separator (Thin Line)
serenity::CreateSeparator::new(false)
Spacing Separator (Thick Line + Space)
serenity::CreateSeparator::new(true)
Usage in Container
let mut components = vec![];
components.push(serenity::CreateContainerComponent::TextDisplay(
serenity::CreateTextDisplay::new("Section 1")
));
components.push(serenity::CreateContainerComponent::Separator(
serenity::CreateSeparator::new(false)
));
components.push(serenity::CreateContainerComponent::TextDisplay(
serenity::CreateTextDisplay::new("Section 2")
));
components.push(serenity::CreateContainerComponent::Separator(
serenity::CreateSeparator::new(true)
));
When to Use
Non-Spacing (false)
- Between closely related sections
- After headers
- Between list items
Spacing (true)
- Between major sections
- Before/after important content
- To create visual breaks
Complete Layout Example
pub fn build_status_message(
enabled: bool,
description: &str,
) -> Vec<serenity::CreateComponent> {
let mut inner_components = vec![];
inner_components.push(serenity::CreateContainerComponent::TextDisplay(
serenity::CreateTextDisplay::new("## Module Configuration")
));
inner_components.push(serenity::CreateContainerComponent::Separator(
serenity::CreateSeparator::new(false)
));
inner_components.push(serenity::CreateContainerComponent::Section(
serenity::CreateSection::new(
vec![
serenity::CreateSectionComponent::TextDisplay(
serenity::CreateTextDisplay::new(format!(
"**Status**: {}\n{}",
if enabled { "Enabled ✅" } else { "Disabled ❌" },
description
))
),
],
serenity::CreateSectionAccessory::Button(
serenity::CreateButton::new("toggle")
.label( enabled { } { })
.( enabled {
serenity::ButtonStyle::Danger
} {
serenity::ButtonStyle::Success
})
),
),
));
inner_components.(serenity::CreateContainerComponent::(
serenity::CreateSeparator::()
));
inner_components.(serenity::CreateContainerComponent::(
serenity::CreateTextDisplay::()
));
[serenity::CreateComponent::(
serenity::CreateContainer::(inner_components)
.( enabled { } { })
)]
}
Architecture Pattern
The codebase follows this pattern consistently:
let mut inner_components: Vec<serenity::CreateContainerComponent> = vec![];
inner_components.push(serenity::CreateContainerComponent::TextDisplay(...));
inner_components.push(serenity::CreateContainerComponent::Separator(...));
inner_components.push(serenity::CreateContainerComponent::Section(...));
let container = serenity::CreateContainer::new(inner_components);
let components = vec![serenity::CreateComponent::Container(container)];
ctx.send(poise::CreateReply::default()
.flags(serenity::MessageFlags::IS_COMPONENTS_V2)
.components(components)
).await?;
Best Practices
- Always use Container - Required wrapper for Components v2
- Set IS_COMPONENTS_V2 flag - Messages will fail without it
- Use Sections for layouts - Text + button horizontal layouts
- Separators for organization - Visual structure and spacing
- Accent colors - Match semantic meaning (green=success, red=danger)
- Max 3 text blocks in Section - Discord limitation
- Build incrementally - Use Vec and push for flexibility
- Consistent spacing - Use separators strategically
Codebase Examples
Container:
src/services/logger.rs:120-122 - Logger message with accent color
src/services/status.rs:166-168 - Status display
src/services/help.rs:78-80 - Help system
src/services/config/mod.rs:212 - Configuration menu
Section:
src/services/config/whitelist.rs:159-169 - Header with back button
src/services/config/builders.rs:61-67 - Module toggle section
src/services/setup/steps/logging.rs:28-38 - Setup step with button
Separator:
src/services/config/mod.rs:73-74 - Non-spacing separator
src/services/logger.rs:96-97 - Spacing separator
src/services/status.rs:59-60 - Visual divider
src/services/help.rs:37-38 - Section separator
See Also
components-v2-content - Text Display, Thumbnail, Media, Files
components-v2-interactive - Buttons, Selects, Action Rows
components-v2-modals - Modals with Labels
Converted and distributed by TomeVault — claim your Tome and manage your conversions.