Como Usar Botões e Menus de Seleção no discord.js
🔍 WiseChecker

Como Usar Botões e Menus de Seleção no discord.js

Bots do Discord podem fazer mais do que apenas responder a comandos de texto. Botões e menus de seleção permitem que os usuários interajam com seu bot por meio de elementos de interface clicáveis. Esses componentes substituem sistemas antigos baseados em reações e oferecem uma experiência de usuário mais limpa. Este artigo explica como configurar e usar botões e menus de seleção com discord.js v14.

Principais Conclusões: Construindo Componentes Interativos para Bot do Discord

  • Classe MessageComponentInteraction: Gerencia todos os cliques em botões e menus de seleção no código do seu bot.
  • ActionRowBuilder: Contêiner obrigatório que pode conter até cinco botões ou um menu de seleção por linha.
  • ButtonBuilder e StringSelectMenuBuilder: Criam os elementos clicáveis com IDs personalizados e rótulos.

O Que São Componentes de Mensagem do Discord?

Componentes de mensagem são elementos de interface interativos que aparecem abaixo da mensagem de um bot em um canal do Discord. Botões são caixas clicáveis que acionam uma ação. Menus de seleção são listas suspensas onde os usuários escolhem uma ou mais opções. Ambos exigem uma string de ID personalizada que seu bot usa para identificar qual componente foi clicado.

Antes de escrever código, você precisa de um bot discord.js v14 funcional. Seu bot deve ter as permissões Enviar Mensagens e Usar Emojis Externos no servidor. Você também precisa do Node.js 16.9.0 ou superior instalado em sua máquina. Os exemplos neste artigo usam o pacote discord.js versão 14.

Pré-requisitos para Usar Componentes

Instale o discord.js v14 na pasta do seu projeto:

npm install discord.js@14

Crie um arquivo básico de bot com as intenções de gateway GatewayIntentBits.Guilds e GatewayIntentBits.MessageContent. Você também precisa dos parciais Partials.Message e Partials.Channel se seu bot lidar com mensagens diretas.

Criando e Enviando um Botão

Botões são construídos com ButtonBuilder e colocados dentro de um ActionRowBuilder. Cada botão precisa de um ID personalizado, um rótulo e um estilo. O estilo controla a cor do botão: Primary é azul, Secondary é cinza, Success é verde, Danger é vermelho e Link abre uma URL.

  1. Importe os construtores necessários
    Adicione estas importações no topo do seu arquivo: const { ButtonBuilder, ButtonStyle, ActionRowBuilder } = require('discord.js');
  2. Crie uma instância do botão
    Use new ButtonBuilder() e encadeie os métodos .setCustomId('meu_botao'), .setLabel('Clique Aqui') e .setStyle(ButtonStyle.Primary).
  3. Envolva o botão em uma linha de ação
    Crie um novo ActionRowBuilder e adicione o botão com .addComponents(botao).
  4. Envie a mensagem com o componente
    Use interaction.reply({ components: [linha] }) ou channel.send({ components: [linha] }) para exibir o botão.

Exemplo de código para um comando de barra que envia um botão:

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

module.exports = {
  data: new SlashCommandBuilder()
    .setName('botao')
    .setDescription('Envia um botão de teste'),
  async execute(interaction) {
    const botao = new ButtonBuilder()
      .setCustomId('botao_primario')
      .setLabel('Clique Aqui')
      .setStyle(ButtonStyle.Primary);

    const linha = new ActionRowBuilder().addComponents(botao);

    await interaction.reply({ content: 'Aqui está seu botão:', components: [linha] });
  }
};

Gerenciando Interações de Botão

Quando um usuário clica em um botão, o Discord envia um evento de interação. Seu bot escuta esse evento usando o manipulador client.on('interactionCreate'). Verifique se a interação é uma ButtonInteraction testando interaction.isButton().

  1. Crie um ouvinte de interação
    No arquivo principal do seu bot, adicione client.on('interactionCreate', async interaction => { ... });
  2. Verifique o tipo de interação
    Dentro do ouvinte, escreva if (!interaction.isButton()) return; para ignorar interações que não são de botão.
  3. Corresponda o ID personalizado
    Use if (interaction.customId === 'botao_primario') para executar código específico para aquele botão.
  4. Responda ou atualize a mensagem
    Chame interaction.reply('Botão clicado!') ou interaction.update({ content: 'Mensagem atualizada' }) para responder.

Exemplo de manipulador para o botão acima:

client.on('interactionCreate', async interaction => {
  if (!interaction.isButton()) return;

  if (interaction.customId === 'botao_primario') {
    await interaction.reply({ content: 'Você clicou no botão!', ephemeral: true });
  }
});

Criando e Enviando um Menu de Seleção

Menus de seleção são construídos com StringSelectMenuBuilder. Cada opção tem um rótulo, um valor e uma descrição opcional. O menu de seleção também precisa de um ID personalizado e um texto de espaço reservado que aparece antes do usuário fazer uma seleção.

  1. Importe o StringSelectMenuBuilder
    Adicione const { StringSelectMenuBuilder, StringSelectMenuOptionBuilder } = require('discord.js');
  2. Crie opções
    Use new StringSelectMenuOptionBuilder().setLabel('Opção 1').setValue('opcao1') para cada opção.
  3. Construa o menu de seleção
    Crie um StringSelectMenuBuilder e encadeie .setCustomId('menu'), .setPlaceholder('Escolha uma opção') e .addOptions(opcao1, opcao2).
  4. Envolva em uma linha de ação
    Crie um ActionRowBuilder com .addComponents(menuSelecao). Uma linha de ação pode conter apenas um menu de seleção.
  5. Envie a mensagem
    Inclua a linha em components ao responder ou enviar uma mensagem.

Exemplo de comando de barra que envia um menu de seleção:

const { SlashCommandBuilder, StringSelectMenuBuilder, StringSelectMenuOptionBuilder, ActionRowBuilder } = require('discord.js');

module.exports = {
  data: new SlashCommandBuilder()
    .setName('menu')
    .setDescription('Envia um menu de seleção'),
  async execute(interaction) {
    const opcao1 = new StringSelectMenuOptionBuilder()
      .setLabel('Vermelho')
      .setValue('vermelho');
    const opcao2 = new StringSelectMenuOptionBuilder()
      .setLabel('Azul')
      .setValue('azul');

    const menuSelecao = new StringSelectMenuBuilder()
      .setCustomId('menu_cores')
      .setPlaceholder('Escolha uma cor')
      .addOptions(opcao1, opcao2);

    const linha = new ActionRowBuilder().addComponents(menuSelecao);

    await interaction.reply({ content: 'Escolha sua cor favorita:', components: [linha] });
  }
};

Gerenciando Interações de Menu de Seleção

Interações de menu de seleção são processadas de forma semelhante aos botões. Verifique interaction.isStringSelectMenu() e leia os valores selecionados de interaction.values, que retorna um array de strings.

  1. Adicione um manipulador de menu de seleção
    No seu ouvinte interactionCreate, adicione if (interaction.isStringSelectMenu()) { ... }.
  2. Obtenha o valor selecionado
    Use const selecionado = interaction.values[0]; para obter a primeira opção escolhida.
  3. Responda com base na seleção
    Use lógica condicional para responder com mensagens diferentes dependendo do valor.

Exemplo de manipulador para o menu de cores:

client.on('interactionCreate', async interaction => {
  if (!interaction.isStringSelectMenu()) return;

  if (interaction.customId === 'menu_cores') {
    const corSelecionada = interaction.values[0];
    await interaction.reply({ content: `Você escolheu ${corSelecionada}`, ephemeral: true });
  }
});

Erros Comuns e Limitações

Limite de Linhas de Ação Excedido

Uma única mensagem pode ter no máximo cinco linhas de ação. Cada linha pode conter até cinco botões ou um menu de seleção. Se você adicionar mais linhas, o Discord retorna um erro. Conte suas linhas antes de enviar.

ID Personalizado Não Único

Se dois botões ou menus na mesma mensagem compartilharem o mesmo ID personalizado, o bot não consegue diferenciá-los. Sempre use IDs personalizados únicos. Para componentes dinâmicos, anexe um identificador único, como um ID de usuário ou um timestamp.

Interação Já Reconhecida

Você pode responder a uma interação apenas uma vez. Se precisar enviar várias mensagens de acompanhamento, use interaction.followUp() após a resposta inicial. Chamar interaction.reply() duas vezes gera um erro.

Valores do Menu de Seleção Devem Ser Únicos

Cada opção em um menu de seleção deve ter um valor de string único. Valores duplicados fazem com que a interação falhe silenciosamente. Sempre verifique se os valores das opções são únicos antes de enviar o menu.

Botões vs Menus de Seleção: Quando Usar Cada Um

Item Botões Menus de Seleção
Número de escolhas Até 5 por linha, 25 por mensagem Até 25 opções por menu
Ação do usuário Clique único Clique e depois selecione na lista suspensa
Melhor para Escolhas binárias, confirmações, navegação Múltiplas opções, listas, configurações
Clareza visual Imediata, todas as opções visíveis Compacta, oculta até abrir

Use botões quando você tiver poucas opções e quiser que os usuários ajam rapidamente. Use menus de seleção quando tiver muitas opções ou precisar economizar espaço em uma mensagem. Você pode combinar ambos em uma única mensagem usando várias linhas de ação.

Agora você sabe como criar botões e menus de seleção com discord.js v14. Comece adicionando um botão simples a um comando de teste e depois expanda para interações de várias etapas. Para uso avançado, tente coletar múltiplas entradas enviando uma sequência de componentes. Desative botões após o uso definindo .setDisabled(true) no construtor do botão para evitar cliques duplos.