| name | components-v2-content |
| description | Guide for content display components (Text, Thumbnail, Media, File) in Discord Components v2 Use when this capability is needed. |
| metadata | {"author":"erdemgksl"} |
Content Components (Components v2)
What this skill does
Reference for displaying static content using Text Display, Thumbnail, Media Gallery, and File components.
When to use
- Display formatted text with Markdown
- Show images and thumbnails
- Display media galleries
- Embed file attachments
- Replace legacy embed fields with modern components
Text Display (Type 10)
What is Text Display?
The primary component for displaying text content. Replaces message content field and embed descriptions.
Supports Markdown: Bold, italic, code blocks, headings, links, etc.
Creating Text Display
Basic Text
use poise::serenity_prelude as serenity;
serenity::CreateTextDisplay::new("Hello World!")
Markdown Text
serenity::CreateTextDisplay::new("**Bold** *italic* `code`")
Headings
serenity::CreateTextDisplay::new("# Main Title")
serenity::CreateTextDisplay::new("## Subtitle")
serenity::CreateTextDisplay::new("### Section")
Multi-line Text
serenity::CreateTextDisplay::new(format!(
"**Status**: Enabled\n\
**Users**: 42\n\
**Last Updated**: <t:{}:R>",
timestamp
))
Dynamic Content
serenity::CreateTextDisplay::new(format!(
"Welcome <@{}>!\nYour role: {}",
user_id,
role_name
))
Usage in Container
let mut components = vec![];
components.push(serenity::CreateContainerComponent::TextDisplay(
serenity::CreateTextDisplay::new("## Configuration")
));
components.push(serenity::CreateContainerComponent::TextDisplay(
serenity::CreateTextDisplay::new("Configure your server settings below.")
));
components.push(serenity::CreateContainerComponent::TextDisplay(
serenity::CreateTextDisplay::new(format!(
"**Guild ID**: `{}`\n\
**Owner**: <@{}>\n\
**Members**: {}",
guild_id, owner_id, member_count
))
));
Usage in Section
serenity::CreateSection::new(
vec![
serenity::CreateSectionComponent::TextDisplay(
serenity::CreateTextDisplay::new(format!(
"**{}**\n{}",
module_name,
description
))
),
],
accessory
)
Common Patterns
Status Display
serenity::CreateTextDisplay::new(format!(
"**Status**: {}\n\
**Uptime**: {}\n\
**Guilds**: {}",
if healthy { "✅ Online" } else { "❌ Offline" },
uptime_str,
guild_count
))
Field List
serenity::CreateTextDisplay::new(format!(
"**User**: <@{}>\n\
**Action**: {}\n\
**Reason**: {}\n\
**Timestamp**: <t:{}:F>",
user_id, action, reason, timestamp
))
Code Block
serenity::CreateTextDisplay::new(format!(
"```json\n{}\n```",
serde_json::to_string_pretty(&data)?
))
Thumbnail (Type 11)
What is Thumbnail?
Displays a small image, typically used as a Section accessory.
Status in Codebase: ❌ Not yet used (but supported by Serenity)
Creating Thumbnail
Basic Thumbnail
serenity::CreateThumbnail::new("https://example.com/image.png")
As Section Accessory
serenity::CreateSection::new(
vec![
serenity::CreateSectionComponent::TextDisplay(
serenity::CreateTextDisplay::new("**User Profile**")
),
],
serenity::CreateSectionAccessory::Thumbnail(
serenity::CreateThumbnail::new(user_avatar_url)
),
)
Potential Use Cases
User Profile
serenity::CreateSection::new(
vec![
serenity::CreateSectionComponent::TextDisplay(
serenity::CreateTextDisplay::new(format!(
"**{}**\nJoined: <t:{}:R>",
user.name, joined_timestamp
))
),
],
serenity::CreateSectionAccessory::Thumbnail(
serenity::CreateThumbnail::new(user.avatar_url())
),
)
Server Info
serenity::CreateSection::new(
vec![
serenity::CreateSectionComponent::TextDisplay(
serenity::CreateTextDisplay::new(format!(
"**{}**\nMembers: {}",
guild.name, guild.member_count
))
),
],
serenity::CreateSectionAccessory::Thumbnail(
serenity::CreateThumbnail::new(guild.icon_url())
),
)
Media Gallery (Type 12)
What is Media Gallery?
Displays multiple images or videos in a gallery layout.
Status in Codebase: ❌ Not yet used (but supported by Serenity)
Creating Media Gallery
Basic Gallery
serenity::CreateMediaGallery::new(vec![
serenity::CreateMediaGalleryItem::new("https://example.com/image1.png"),
serenity::CreateMediaGalleryItem::new("https://example.com/image2.png"),
])
Multiple Images
let items: Vec<_> = image_urls
.iter()
.map(|url| serenity::CreateMediaGalleryItem::new(url))
.collect();
serenity::CreateMediaGallery::new(items)
Usage in Container
components.push(serenity::CreateContainerComponent::MediaGallery(
serenity::CreateMediaGallery::new(vec![
serenity::CreateMediaGalleryItem::new("https://cdn.discordapp.com/attachments/.../image1.png"),
serenity::CreateMediaGalleryItem::new("https://cdn.discordapp.com/attachments/.../image2.png"),
])
));
Potential Use Cases
Violation Evidence
let screenshots = vec![
"https://cdn.example.com/screenshot1.png",
"https://cdn.example.com/screenshot2.png",
];
let gallery_items: Vec<_> = screenshots
.iter()
.map(|url| serenity::CreateMediaGalleryItem::new(*url))
.collect();
components.push(serenity::CreateContainerComponent::MediaGallery(
serenity::CreateMediaGallery::new(gallery_items)
));
Audit Log Attachments
serenity::CreateMediaGallery::new(vec![
serenity::CreateMediaGalleryItem::new(before_image_url),
serenity::CreateMediaGalleryItem::new(after_image_url),
])
File (Type 13)
What is File?
Embeds a file attachment directly into the message body.
Status in Codebase: ❌ Not yet used (but supported by Serenity)
Creating File Component
Basic File
serenity::CreateFile::new(
"https://example.com/document.pdf",
"document.pdf"
)
With Custom Filename
serenity::CreateFile::new(
attachment_url,
format!("export_{}.json", timestamp)
)
Usage in Container
components.push(serenity::CreateContainerComponent::File(
serenity::CreateFile::new(
"https://cdn.discordapp.com/attachments/.../config.json",
"server_config.json"
)
));
Potential Use Cases
Configuration Export
let config_json = serde_json::to_string_pretty(&guild_config)?;
components.push(serenity::CreateContainerComponent::File(
serenity::CreateFile::new(uploaded_url, "config.json")
));
Log Export
components.push(serenity::CreateContainerComponent::File(
serenity::CreateFile::new(
log_file_url,
format!("audit_log_{}.txt", guild_id)
)
));
Backup Files
serenity::CreateFile::new(
backup_url,
format!("backup_{}_{}.zip", guild_id, timestamp)
)
Complete Content Example
pub fn build_user_profile(
user: &serenity::User,
joined_at: i64,
roles: &[String],
) -> Vec<serenity::CreateComponent> {
let mut inner_components = vec![];
inner_components.push(serenity::CreateContainerComponent::TextDisplay(
serenity::CreateTextDisplay::new(format!("## {}", user.name))
));
inner_components.push(serenity::CreateContainerComponent::Separator(
serenity::CreateSeparator::new(false)
));
inner_components.push(serenity::CreateContainerComponent::TextDisplay(
serenity::CreateTextDisplay::new(format!(
"**ID**: `{}`\n\
**Joined**: <t:{}:R>\n\
**Mention**: <@{}>",
user.id, joined_at, user.id
))
));
inner_components.push(serenity::CreateContainerComponent::Separator(
serenity::CreateSeparator::new(true)
));
inner_components.push(serenity::CreateContainerComponent::TextDisplay(
serenity::CreateTextDisplay::new("**Roles**")
));
inner_components.(serenity::CreateContainerComponent::(
serenity::CreateTextDisplay::(roles.())
));
[serenity::CreateComponent::(
serenity::CreateContainer::(inner_components)
.()
)]
}
Markdown Reference
Text Display supports Discord Markdown:
**bold**
*italic*
__underline__
~~strikethrough~~
`code`
```code block```
# Heading 1
## Heading 2
### Heading 3
[link](https://example.com)
<@user_id> - User mention
<@&role_id> - Role mention
<#channel_id> - Channel mention
<t:timestamp:F> - Timestamp (full date)
<t:timestamp:R> - Timestamp (relative)
Best Practices
- Use Text Display everywhere - Replaces content/embed description
- Markdown for formatting - Bold headers, italic notes
- Mention syntax - Use
<@user_id> not @username
- Timestamps - Use
<t:unix:format> for dates
- Code blocks - Triple backticks for formatted code/JSON
- Multi-line for fields - Use
\n for field-style layouts
- Thumbnail for avatars - Small images as section accessories
- Media Gallery for multiple - Use gallery for 2+ images
- File for downloads - Embed downloadable attachments
Codebase Examples
Text Display:
src/services/config/mod.rs:58-59 - Simple label
src/services/status.rs:55-56 - Heading with Markdown
src/services/logger.rs:92-93 - Multi-line content
src/services/config/builders.rs:63-64 - Formatted field
Separators:
src/services/config/mod.rs:73-74 - Non-spacing
src/services/logger.rs:96-97 - Spacing separator
Container Usage:
src/services/logger.rs:120-122 - Logger message
src/services/status.rs:166-168 - Status display
src/services/help.rs:78-80 - Help menu
Migration from Legacy Embeds
Old (Legacy Embed)
ctx.send(poise::CreateReply::default()
.embed(serenity::CreateEmbed::new()
.title("Title")
.description("Description")
.field("Field 1", "Value 1", false)
.color(0x5865F2)
)
).await?;
New (Components v2)
let mut components = vec![];
components.push(serenity::CreateContainerComponent::TextDisplay(
serenity::CreateTextDisplay::new("## Title")
));
components.push(serenity::CreateContainerComponent::TextDisplay(
serenity::CreateTextDisplay::new("Description")
));
components.push(serenity::CreateContainerComponent::Separator(
serenity::CreateSeparator::new(false)
));
components.push(serenity::CreateContainerComponent::TextDisplay(
serenity::CreateTextDisplay::new("**Field 1**\nValue 1")
));
ctx.send(poise::CreateReply::default()
.flags(serenity::MessageFlags::IS_COMPONENTS_V2)
.components(vec![serenity::CreateComponent::Container(
serenity::CreateContainer::new(components)
.accent_color(0x5865F2)
)])
).await?;
See Also
components-v2-layout - Container, Section, Separator
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.