aslain.dev
0%
01 Hizmetler 02 Hakkımda 03 Projeler 04 Stack 05 Blog 06 İletişim
← Tüm makaleler Bots Discord

Boutons et menus déroulants de bot Discord

Ajouter un bouton de bot Discord transforme vos messages de simples pavés de texte en véritable interface : l'utilisateur clique, le bot réagit instantanément. Avec discord.js, les boutons, les menus déroulants (string select) et les composants ActionRow qui les portent permettent de construire des flux interactifs : sélecteurs de rôle, pagination, fenêtres de confirmation ou panneaux de tickets de support. Dans ce guide, vous allez créer les composants de zéro, écouter correctement les clics après l'envoi, et apprendre à éviter les erreurs les plus courantes.

Le modèle de composants : ActionRow, bouton et select

Sur Discord, les éléments interactifs ne sont jamais attachés directement au message : ils se placent dans des lignes (rows). Un message peut contenir au maximum 5 ActionRows. Chaque ligne porte soit jusqu'à cinq boutons, soit un seul menu déroulant ; vous ne pouvez pas mélanger les deux dans la même ligne. Dans discord.js v14, vous construisez ces structures avec les classes builder :

  • ButtonBuilder — un bouton cliquable avec un style, un libellé et un customId.
  • StringSelectMenuBuilder — un menu déroulant à options fixes.
  • ActionRowBuilder — le conteneur qui regroupe les composants.

Les styles de bouton viennent de l'enum ButtonStyle : Primary (bleu), Secondary (gris), Success (vert), Danger (rouge) et Link. Les boutons Link ouvrent une URL et ne prennent pas de customId ; les autres génèrent des interactions.

Créer un bouton de bot Discord

L'exemple ci-dessous ajoute deux boutons à une commande slash. Le champ customId est l'élément clé : c'est l'identifiant unique qui vous permet de distinguer les événements de clic, et il peut atteindre 100 caractères.

const {
  ButtonBuilder,
  ButtonStyle,
  ActionRowBuilder,
} = require('discord.js');

const confirm = new ButtonBuilder()
  .setCustomId('order_confirm')
  .setLabel('Confirmer')
  .setStyle(ButtonStyle.Success);

const cancel = new ButtonBuilder()
  .setCustomId('order_cancel')
  .setLabel('Annuler')
  .setStyle(ButtonStyle.Danger);

const row = new ActionRowBuilder().addComponents(confirm, cancel);

await interaction.reply({
  content: 'Voulez-vous confirmer la commande ?',
  components: [row],
});

Le message affiche désormais deux boutons. Mais ils sont encore « morts » : pour que quelque chose se passe au clic, vous devez mettre en place un écouteur séparé.

Ajouter un menu déroulant string select

Un menu déroulant est plus net que des boutons quand vous voulez proposer plusieurs options à l'utilisateur. Chaque option a un libellé visible et une value qui vous est renvoyée. En option, vous pouvez activer la sélection multiple avec setMinValues et setMaxValues.

const { StringSelectMenuBuilder } = require('discord.js');

const menu = new StringSelectMenuBuilder()
  .setCustomId('role_select')
  .setPlaceholder('Choisissez un rôle')
  .addOptions(
    { label: 'Développeur', value: 'dev', emoji: '💻' },
    { label: 'Designer', value: 'design', emoji: '🎨' },
    { label: 'Communauté', value: 'community', emoji: '🤝' },
  );

const menuRow = new ActionRowBuilder().addComponents(menu);
await interaction.reply({ components: [menuRow] });

Un menu déroulant remplit une ligne entière à lui seul ; vous ne pouvez pas y ajouter de bouton. Si vous voulez plusieurs menus ou groupes de boutons, créez des objets ActionRowBuilder distincts et ajoutez-les tous au tableau components.

Écouter les interactions : interactionCreate et collectors

Il existe deux façons de capter les clics. Pour des boutons permanents, toujours actifs, utilisez l'événement principal interactionCreate du bot et aiguillez selon le customId :

client.on('interactionCreate', async (interaction) => {
  if (interaction.isButton()) {
    if (interaction.customId === 'order_confirm') {
      await interaction.reply({ content: 'Commande confirmée ✅', ephemeral: true });
    }
  }

  if (interaction.isStringSelectMenu() && interaction.customId === 'role_select') {
    const choice = interaction.values[0];
    await interaction.reply({ content: `Votre choix : ${choice}`, ephemeral: true });
  }
});

Pour des flux temporaires liés à un message précis (pagination ou confirmation unique), createMessageComponentCollector est plus pratique. Un collector se ferme après un délai défini et n'écoute que les composants de ce message :

const reply = await interaction.fetchReply();
const collector = reply.createMessageComponentCollector({
  time: 60_000,
});

collector.on('collect', async (i) => {
  if (i.user.id !== interaction.user.id) {
    return i.reply({ content: 'Ce menu n\'est pas pour vous.', ephemeral: true });
  }
  await i.update({ content: `Choix : ${i.customId}`, components: [] });
});

collector.on('end', () => {
  reply.edit({ components: [] }).catch(() => {});
});

Répondez toujours à chaque interaction

Discord attend une réponse à une interaction dans un délai de 3 secondes ; sinon, l'utilisateur voit l'erreur « Cette interaction a échoué ». Si vous ne pouvez pas répondre aussi vite (requête de base de données, appel d'API externe, etc.), appelez d'abord deferUpdate() ou deferReply(), puis poursuivez avec editReply(). Distinguez les méthodes de réponse ainsi :

  • reply() — envoie une nouvelle réponse.
  • update() — modifie le message d'origine où se trouvait le bouton (idéal pour fermer les menus).
  • deferUpdate() / deferReply() — un état « en réflexion » qui gagne du temps pour les opérations longues.

L'option ephemeral: true affiche la réponse uniquement à la personne qui a cliqué, ce qui garde le salon propre pour les panneaux de rôle et les messages d'erreur.

Questions fréquentes

Pourquoi customId est-il si important ?

Parce que le customId est le seul moyen de savoir quel bouton ou quel menu a été cliqué. Gardez-le unique et lisible ; au besoin, vous pouvez y intégrer des données (un id d'utilisateur ou de message) comme ticket_close_12345 et l'analyser au moment du clic.

Combien de boutons un message peut-il contenir ?

Jusqu'à 5 ActionRows par message et jusqu'à 5 boutons par ligne de boutons, soit 25 boutons au total. Un menu déroulant, en revanche, remplit une ligne à lui seul.

Les anciens boutons cessent-ils de fonctionner après un redémarrage du bot ?

Les collectors sont liés au bot en cours d'exécution, ils sont donc perdus au redémarrage. Pour des boutons permanents, utilisez un écouteur global interactionCreate avec un routage basé sur le customId plutôt qu'un collector ; ainsi, les clics restent traités à chaque démarrage du bot.

Besoin d'un bot Discord interactif ? Je peux mettre en place une configuration propre et maintenable pour des panneaux de rôle, des systèmes de tickets ou des flux de menus déroulants personnalisés. Contactez-moi et parlons de votre projet.

Bu kategorideki tüm yazılar →

Devamı için