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.