Discord's Components V2 system allows you to create rich, interactive, and visually appealing messages entirely with components — no embeds required.
This guide walks you through the main component types, usage examples, and includes a full slash command demonstration.
Components V2 are UI building blocks for Discord messages.
They allow you to:
- Display formatted text
- Group content into sections
- Add interactive elements like buttons and menus
- Show media galleries
- Attach files
- Organize information with separators
Static text with Markdown formatting.
const { TextDisplayBuilder } = require('discord.js');
const textDisplay = new TextDisplayBuilder().setContent('📝 **This is a TextDisplay component.**');
Visual space or divider between components.
const { SeparatorBuilder, SeparatorSpacingSize } = require('discord.js');
const separator = new SeparatorBuilder().setDivider(true).setSpacing(SeparatorSpacingSize.Small);
Groups text, optionally with a thumbnail or button.
const { SectionBuilder, TextDisplayBuilder, ThumbnailBuilder } = require('discord.js');
const section = new SectionBuilder()
.addTextDisplayComponents(
new TextDisplayBuilder().setContent('📄 **Section Title**'),
new TextDisplayBuilder().setContent('This is a section description.')
)
.setThumbnailAccessory(new ThumbnailBuilder({ media: { url: 'https://example.com/image.png' } }));
Small image beside section text.
const { ThumbnailBuilder } = require('discord.js');
const thumbnail = new ThumbnailBuilder({ media: { url: 'https://example.com/avatar.png' } });
Clickable link or action.
const { ButtonBuilder, ButtonStyle } = require('discord.js');
// Link button
const linkButton = new ButtonBuilder()
.setLabel('Docs')
.setURL('https://discord.com/developers/docs/components/overview')
.setStyle(ButtonStyle.Link);
Dropdown to select a channel.
const { ChannelSelectMenuBuilder } = require('discord.js');
const menu = new ChannelSelectMenuBuilder()
.setCustomId('channel_select_menu')
.setPlaceholder('Select a channel…');
Carousel of images/videos.
const { MediaGalleryBuilder, MediaGalleryItemBuilder } = require('discord.js');
const gallery = new MediaGalleryBuilder().addItems(
new MediaGalleryItemBuilder().setURL('https://example.com/image1.png'),
new MediaGalleryItemBuilder().setURL('https://example.com/image2.png')
);
Attach and reference a file.
const { FileBuilder, AttachmentBuilder } = require('discord.js');
const file = new AttachmentBuilder('./example.json').setName('example.json');
const fileComponent = new FileBuilder().setURL('attachment://example.json');
Groups multiple components in one.
const { ContainerBuilder, TextDisplayBuilder, SeparatorBuilder, SeparatorSpacingSize } = require('discord.js');
const container = new ContainerBuilder()
.setAccentColor(0x5865F2)
.addTextDisplayComponents(new TextDisplayBuilder().setContent('Hello from a container!'))
.addSeparatorComponents(new SeparatorBuilder().setDivider(true).setSpacing(SeparatorSpacingSize.Small));
const {
SlashCommandBuilder,
MessageFlags,
TextDisplayBuilder,
SeparatorBuilder,
SeparatorSpacingSize,
ThumbnailBuilder,
SectionBuilder,
ChannelSelectMenuBuilder,
ActionRowBuilder,
ContainerBuilder,
MediaGalleryBuilder,
MediaGalleryItemBuilder,
ButtonBuilder,
ButtonStyle,
FileBuilder,
AttachmentBuilder
} = require('discord.js');
const path = require('path');
const config = require('../../config/config.json');
module.exports = {
data: new SlashCommandBuilder()
.setName('v2-components')
.setDescription('Demonstrates all V2 components'),
async execute(interaction, client) {
const botAvatar = client.user.displayAvatarURL({ extension: 'png', size: 512 });
const textDisplay = new TextDisplayBuilder().setContent('🔹 TextDisplay example');
const separator = new SeparatorBuilder().setDivider(true).setSpacing(SeparatorSpacingSize.Small);
const sectionThumb = new SectionBuilder()
.addTextDisplayComponents(
new TextDisplayBuilder().setContent('📄 **Section Title**'),
new TextDisplayBuilder().setContent('Description with thumbnail.')
)
.setThumbnailAccessory(new ThumbnailBuilder({ media: { url: botAvatar } }));
const selectMenu = new ActionRowBuilder().addComponents(
new ChannelSelectMenuBuilder().setCustomId('channel_select').setPlaceholder('Select a channel…')
);
const mediaGallery = new MediaGalleryBuilder().addItems(
new MediaGalleryItemBuilder().setURL('https://example.com/image1.png'),
new MediaGalleryItemBuilder().setURL('https://example.com/image2.png')
);
const sectionButtons = [
new SectionBuilder().addTextDisplayComponents(new TextDisplayBuilder().setContent('🔗 **Docs**'))
.setButtonAccessory(new ButtonBuilder().setLabel('Overview').setURL('https://discord.com/developers/docs/components/overview').setStyle(ButtonStyle.Link)),
new SectionBuilder().addTextDisplayComponents(new TextDisplayBuilder().setContent('📑 **Reference**'))
.setButtonAccessory(new ButtonBuilder().setLabel('Types').setURL('https://discord.com/developers/docs/components/reference#what-is-a-component-component-types').setStyle(ButtonStyle.Link)),
new SectionBuilder().addTextDisplayComponents(new TextDisplayBuilder().setContent('🚀 **Getting Started**'))
.setButtonAccessory(new ButtonBuilder().setLabel('Guide').setURL('https://discord.com/developers/docs/components/using-message-components').setStyle(ButtonStyle.Link))
];
const filePath = path.join(__dirname, '../../assets/embed-export.json');
const attachment = new AttachmentBuilder(filePath).setName('embed-export.json');
const fileComponent = new FileBuilder().setURL('attachment://embed-export.json');
const container = new ContainerBuilder()
.setAccentColor(parseInt(config.color.replace('#', ''), 16))
.addMediaGalleryComponents(mediaGallery)
.addSectionComponents(sectionThumb)
.addMediaGalleryComponents(new MediaGalleryBuilder().addItems(new MediaGalleryItemBuilder().setURL(botAvatar)))
.addSectionComponents(...sectionButtons)
.addSeparatorComponents(new SeparatorBuilder().setDivider(true).setSpacing(SeparatorSpacingSize.Small))
.addTextDisplayComponents(
new TextDisplayBuilder().setContent('📝 **Fully composed with Components V2**'),
new TextDisplayBuilder().setContent('- TextDisplay: static text'),
new TextDisplayBuilder().setContent('- Section: grouped text/accessories'),
new TextDisplayBuilder().setContent('- MediaGallery: images'),
new TextDisplayBuilder().setContent('- Separator: content dividers'),
new TextDisplayBuilder().setContent('- File: attachments'),
new TextDisplayBuilder().setContent('- Button: actions/links'),
new TextDisplayBuilder().setContent('- ChannelSelectMenu: choose channels')
)
.addFileComponents(fileComponent);
await interaction.reply({
flags: MessageFlags.IsComponentsV2,
components: [textDisplay, separator, sectionThumb, selectMenu, container],
files: [attachment]
});
}
};
- Group related items in containers for structure.
- Use separators for better readability.
- Keep text short for mobile users.
- Use buttons for quick links and actions.
- Ensure all URLs are valid and accessible.
- Reference attached files using
attachment://filename
.