Components
Discord components are interactive elements such as buttons, drop-down menus and text fields that developers can integrate into messages sent by bots.
They allow users to interact directly with bots in a more intuitive and dynamic way, improving the user experience by making interactions more engaging and responsive.
Buttons
Buttons in Discord are used to allow users to interact with the interface and perform actions. For example, a button might be used to send a message, join a voice channel, or initiate a game.
You can read the entire documentation about buttons here.
Guidelines
- 34 characters max with icon or emoji.
- 38 characters max without icon or emoji.
- Keep text concise and to the point.
- Use clear and easily understandable language. Avoid jargon or overly technical terms.
- Use verbs that indicate the outcome of the action.
- Maintain consistency in language and tone across buttons.
- Anticipate the need for translation, test for expansion or contraction in different languages.
Types
action
: which allow you to create an interactionlink
: which allow you to open a urlpremium
: which allow you to buy a premium subscription
Builders
Action buttons are buttons that allow you to interact with the bot.
You should define label
or emoji
property.
Property | Description | Required |
---|---|---|
label | The text displayed on the button. | No |
emoji | The emoji displayed on the button. | No |
disabled | Whether the button is disabled. | No |
Primary button
Used for the main actions that the user needs to perform, often visually highlighted.
final primary = ButtonBuilder.primary('primary')
..setLabel('Click me')
..setEmoji(PartialEmoji.fromUnicode('👍'))
..setDisabled(true);
Secondary button
Used for secondary actions, less important than those of primary buttons.
final secondary = ButtonBuilder.secondary('secondary')
..setLabel('Click me')
..setEmoji(PartialEmoji.fromUnicode('🚀'))
..setDisabled(true);
Success button
Used to indicate a successful or positive action, often associated with confirmations.
final success = ButtonBuilder.success('success')
..setLabel('Click me')
..setEmoji(PartialEmoji.fromUnicode('✅'))
..setDisabled(true);
Danger button
Used for critical or destructive actions, such as deleting data.
final danger = ButtonBuilder.danger('danger')
..setLabel('Click me')
..setEmoji(PartialEmoji.fromUnicode('❌'))
..setDisabled(true);
Link button
Used to redirect the user to an external URL without triggering an internal action.
You should define url
property.
final link = ButtonBuilder.link()
..setLabel('Click me')
..setUrl('https://google.com');
Premium button
Used to allow users to buy a premium subscription.
final premium = ButtonBuilder.premium('sku_id');
Sending buttons
No more than 5 components can be registered in a single RowBuilder
.
await channel.send(
content: 'Hello World !',
components: [
RowBuilder()
..addComponent(primary)
..addComponent(secondary)
..addComponent(success)
..addComponent(danger)
..addComponent(link)
]);
Dialogs
Modals in Discord are interactive pop-up windows that allow users to input information or make specific choices.
They are used for more complex interactions, such as filling out forms or confirming important actions, enhancing the user experience by providing a richer and more intuitive interface.
The customId
property is mandatory for dialogs.
Text input
Field customId
property is mandatory for text.
final text = DialogTextInput('customId')
..setLabel('Hello')
..setPlaceholder('World')
..setConstraint(
minLength: 1,
maxLength: 255,
required: true
);
Paragraph input
Field customId
property is mandatory for paragraph.
final paragraph = DialogParagraphInput('customId')
..setLabel('Hello')
..setPlaceholder('World')
..setConstraint(
minLength: 1,
maxLength: 255,
required: true
);
Dialog builder
final dialog = DialogBuilder('customId')
..setTitle('Hello Mineral')
..text(
customId: 'title',
title: 'Title',
defaultValue: post.title)
..paragraph(
customId: 'content',
title: 'Content',
constraint: DialogFieldConstraint(
minLength: 1,
maxLength: 255,
required: true
));
Sending dialogs
Dialogs in Discord can only be used in response to a user interaction.
This means they must be triggered by a specific user action, such as clicking a button or using a command.
This restriction ensures that dialogs are always relevant and contextual, thereby enhancing the user experience by providing information or choices at the appropriate time.
final dialog = DialogBuilder('customId')
..setTitle('Hello')
..text('hello', (input) {
input
..setLabel('Hello')
..setPlaceholder('World')
..setConstraint(
minLength: 1,
maxLength: 255,
required: true
);
});
await ctx.interaction.dialog(dialog);
Handing dialogs
Basiquement, vous pouvez écouter l'évènement de deux manières différentes.
Par défaut, l'évènement catch l'ensemble des interactions de type ServerDialogSubmitEvent
.
final class MyDialogEvent extends ServerDialogSubmitEvent {
FutureOr<void> handle(ctx, options) {
// Handle dialog submit
}
}
client.events.server.dialogSubmit((ctx, options) {
// Handle dialog submit
});
However, it is possible to choose just one component to listen to, using its customId
.
final class MyDialogEvent implements ServerDialogSubmitEvent {
@override
String? get customId => 'customId';
@override
FutureOr<void> handle(ctx, options) {
// Handle dialog submit when customId is 'customId'
}
}
client.events.server.dialogSubmit((ctx, options) {
// Handle dialog submit when customId is 'customId'
});
}, customId: 'customId');
Select menus
Selection menus in Discord are interactive elements that allow users to choose from a list of predefined options.
They are used for more complex interactions where multiple choices are possible, enhancing the user experience by providing a richer, more intuitive interface.
Execution context
The action resulting from the user's choice is carried out in a certain interaction context which influences the information available to the user.
There are currently 2 types of interaction context:
ServerSelectContext
: Interaction context for servers.PrivateSelectContext
: Interaction context for private messages.
Text menu
final helloEmoji = PartialEmoji.fromUnicode('👋');
final worldEmoji = PartialEmoji.fromUnicode('🌍');
final select = SelectMenuBuilder.text('customId')
..setPlaceholder('World')
..addOption(label: 'Hello', value: 'hello', emoji: helloEmoji)
..addOption(label: 'World', value: 'world', emoji: worldEmoji);
final select = SelectMenuBuilder.text('customId');
final row = RowBuilder()
..addComponent(select);
await ctx.interaction.reply(
content: 'Hello World',
components: [row]
);
client.events.server.selectText((ctx, values) async {
await ctx.interaction.reply(
content: 'Find ${values.length} values $values',
ephemeral: true
);
}, customId: 'customId');
// ⚠️ Don't forget to register the event in your main file
final class MyTextSelect extends ServerTextSelectEvent {
@override
String get customId => 'customId';
@override
FutureOr<void> handle(ServerSelectContext ctx, List<String> values) {
await ctx.interaction.reply(
content: 'Find ${values.length} values $values',
ephemeral: true
);
}
}
Channel menu
final select = SelectMenuBuilder.channel('customId')
..setPlaceholder('World')
..setChannelTypes([ChannelType.guildCategory]);
final select = SelectMenuBuilder.text('customId');
final row = RowBuilder()
..addComponent(select);
await ctx.interaction.reply(
content: 'Hello World',
components: [row]
);
client.events.server.selectText((ctx, channels) async {
final channelNames = channels.map((channel) => channel.name);
await ctx.interaction.reply(
content: 'Find ${values.length} channels $channelNames',
ephemeral: true
);
}, customId: 'customId');
// ⚠️ Don't forget to register the event in your main file
final class MyChannelSelect extends ServerChannelSelectEvent {
@override
String get customId => 'customId';
@override
FutureOr<void> handle(ServerSelectContext ctx, List<ServerChannel> channels) {
final channelNames = channels.map((channel) => channel.name);
await ctx.interaction.reply(
content: 'Find ${values.length} channels $channelNames',
ephemeral: true
);
}
}