Bir Discord botunu sadece komut yanıtlayan bir araçtan kullanışlı bir arayüze dönüştüren şey bileşenlerdir (components): onay butonları, rol seçme menüleri, başvuru formları. Kullanıcı bir butona bastığında, menüden seçim yaptığında ya da bir formu gönderdiğinde botunuza yeni bir interaction gelir ve bunu tıpkı slash komut gibi yanıtlamanız gerekir.

Bu rehberde Discord'un resmî Component Reference belgesi ve discord.js rehberi ışığında butonların stillerini, beş farklı select menu türünü, modal içinde kullanılabilen güncel bileşenleri, custom_id sınırlarını ve bu etkileşimleri collector ile mi yoksa kalıcı bir dinleyiciyle mi karşılamanız gerektiğini anlatıyoruz. Komut tarafını henüz kurmadıysanız önce slash komut oluşturma yazısına göz atın.

custom_id: her bileşenin kimliği

Buton ve select menu gibi etkileşimli bileşenler bir custom_id taşır. Bunu siz belirlersiniz; kullanıcı bileşeni kullandığında Discord aynı değeri interaction ile geri gönderir. Belgeye göre custom_id 1-100 karakterlik bir string'dir ve aynı mesajdaki bileşenler aynı custom_id'yi paylaşamaz. Modal'ın kendi custom_id'si de 1-100 karakterdir.

Ayrıca her bileşen isteğe bağlı, 32 bitlik sayısal bir id alanı alabilir. Bu, custom_id'den farklıdır: mesaj içindeki bileşeni tanımlamak için kullanılır, verilmezse Discord sırayla doldurur.

Butonlar: stiller ve kurallar

Butonlar: stiller ve kurallar: Link butonları custom_id alamaz ve tıklandığında botunuza interaction göndermez., Premium butonlar sku_id içermek zorundadır; custom_id, label, url...

Buton yalnızca mesajlarda kullanılabilir ve bir Action Row içine ya da Components V2'deki bir Section'ın accessory alanına yerleştirilir. Bir Action Row en fazla 5 buton taşır. Buton etiketi en fazla 80 karakter, link URL'si en fazla 512 karakterdir.

StilDeğerKullanımGerekli alan
Primary1Gruptaki en önemli eylemcustom_id
Secondary2Alternatif ya da destekleyici eylemcustom_id
Success3Olumlu onaycustom_id
Danger4Geri alınamaz eylem (ban, silme)custom_id
Link5Bir URL açarurl
Premium6Satın almasku_id
  • Link butonları custom_id alamaz ve tıklandığında botunuza interaction göndermez.
  • Premium butonlar sku_id içermek zorundadır; custom_id, label, url veya emoji alamaz ve interaction göndermez. Mağaza simgesi, SKU adı ve fiyatı otomatik gösterilir. Ayrıntı: Discord uygulama premium abonelik.
  • Discord'un tasarım önerisi: bir grupta yalnızca bir Primary buton kullanın; eşit önemdeki butonlar için Secondary seçin.
  • setDisabled(true) butonu mesajdan kaldırmadan devre dışı bırakır.
javascript
const { ActionRowBuilder, ButtonBuilder, ButtonStyle } = require('discord.js');

const onay = new ButtonBuilder()
  .setCustomId(`ban:onay:${hedef.id}`)
  .setLabel('Banla')
  .setStyle(ButtonStyle.Danger);

const iptal = new ButtonBuilder()
  .setCustomId('ban:iptal')
  .setLabel('Vazgeç')
  .setStyle(ButtonStyle.Secondary);

const kurallar = new ButtonBuilder()
  .setLabel('Sunucu kuralları')
  .setURL('https://example.com/kurallar')
  .setStyle(ButtonStyle.Link);

const satir = new ActionRowBuilder().addComponents(iptal, onay, kurallar);
await interaction.reply({ content: `${hedef} banlansın mı?`, components: [satir] });

Select menu türleri

Select menu, bir Action Row'un içinde tek başına durur; yani her menü kendi satırını ister. Beş türü vardır:

Tür (değer)discord.js builderSeçenekler nereden gelir
String Select (3)StringSelectMenuBuilderSizin tanımladığınız en fazla 25 seçenek
User Select (5)UserSelectMenuBuilderSunucudaki kullanıcılar, otomatik
Role Select (6)RoleSelectMenuBuilderSunucudaki roller, otomatik
Mentionable Select (7)MentionableSelectMenuBuilderKullanıcılar ve roller birlikte
Channel Select (8)ChannelSelectMenuBuilderKanallar; setChannelTypes ile filtrelenir
  • min_values / max_values: Varsayılan 1, en fazla 25. Çoklu seçim için setMinValues() ve setMaxValues() kullanılır; seçilen değerler kullanıcı menünün dışına tıkladığında tek interaction olarak gelir.
  • placeholder: En fazla 150 karakter.
  • String Select seçenekleri: label, value ve description en fazla 100 karakter; isteğe bağlı emoji ve default.
  • default_values: Otomatik dolan menülerde (user, role, mentionable, channel) önceden seçili değerler verebilirsiniz.
javascript
const { ActionRowBuilder, StringSelectMenuBuilder, StringSelectMenuOptionBuilder, RoleSelectMenuBuilder } = require('discord.js');

const oyunMenu = new StringSelectMenuBuilder()
  .setCustomId('oyun-sec')
  .setPlaceholder('Oynadığınız oyunları seçin')
  .setMinValues(1)
  .setMaxValues(3)
  .addOptions(
    new StringSelectMenuOptionBuilder().setLabel('Minecraft').setValue('minecraft'),
    new StringSelectMenuOptionBuilder().setLabel('Valorant').setValue('valorant'),
    new StringSelectMenuOptionBuilder().setLabel('CS2').setValue('cs2'),
  );

const rolMenu = new RoleSelectMenuBuilder().setCustomId('rol-sec').setPlaceholder('Bir rol seçin');

await interaction.reply({
  content: 'Tercihlerinizi seçin:',
  components: [
    new ActionRowBuilder().addComponents(oyunMenu),
    new ActionRowBuilder().addComponents(rolMenu),
  ],
});

Seçilen değerler interaction.values dizisinde gelir. String Select için bu dizide sizin value değerleriniz, diğer türlerde ise seçilen nesnelerin ID'leri bulunur.

Etkileşimleri karşılamak: collector mı, global handler mı?

Bileşen interaction'ları da 3 saniye içinde yanıtlanmalıdır. discord.js rehberi üç yol sunar:

YöntemNe zaman uygunDezavantajı
awaitMessageComponent()Tek bir yanıt beklenen akışlar: onay / iptalZaman aşımında hata fırlatır; bot yeniden başlarsa bekleme kaybolur
createMessageComponentCollector()Belirli bir süre boyunca çok sayıda etkileşim: anket, sayfalamaBellekte yaşar; yeniden başlatmada kaybolur
Events.InteractionCreate dinleyicisiKalıcı arayüzler: rol menüsü, destek talebi butonuDurumu custom_id ya da veritabanında kendiniz taşımalısınız
javascript
// 1) Tek seferlik onay: awaitMessageComponent
const yanit = await interaction.reply({ content: 'Emin misiniz?', components: [satir], withResponse: true });
try {
  const tik = await yanit.resource.message.awaitMessageComponent({
    filter: (i) => i.user.id === interaction.user.id,
    time: 60_000,
  });
  await tik.update({ content: tik.customId.startsWith('ban:onay') ? 'Banlandı.' : 'İptal edildi.', components: [] });
} catch {
  await interaction.editReply({ content: '1 dakika içinde yanıt gelmedi.', components: [] });
}

// 2) Kalıcı handler: bot yeniden başlasa da çalışır
client.on(Events.InteractionCreate, async (i) => {
  if (i.isButton() && i.customId === 'destek-ac') {
    await i.reply({ content: 'Destek talebiniz açıldı.', flags: MessageFlags.Ephemeral });
  } else if (i.isStringSelectMenu() && i.customId === 'oyun-sec') {
    await i.update({ content: `Seçiminiz: ${i.values.join(', ')}`, components: [] });
  }
});
  • update(): Bileşenin bağlı olduğu mesajı düzenleyerek interaction'ı yanıtlar. Mesajı yerinde değiştirmek için en doğru yoldur.
  • deferUpdate(): Yanıtı erteler ve kullanıcıya yükleniyor durumu göstermez; işlem sonrası editReply() ya da followUp() kullanılır.
  • filter: Onay butonlarında yalnızca komutu çalıştıran kişinin basabilmesi için i.user.id === interaction.user.id filtresi kullanın.
  • Komut, buton ve modal yanıtlarındaki zamanlama hataları için etkileşim başarısız oldu hatası yazısına bakın.

Mesaj başına sınırlar

  • Klasik (legacy) mesajlarda en fazla 5 Action Row üst düzey bileşen olabilir.
  • Bir Action Row ya en fazla 5 buton ya da tek bir select menu içerir.
  • Components V2 bayrağıyla gönderilen mesajlarda toplam 40 bileşene kadar çıkılabilir ve butonlar Section içinde metnin yanında da durabilir. Ayrıntılar: Components V2 nedir.
  • Webhook ile bileşen gönderiyorsanız belge ?with_components=true sorgu parametresini istiyor; yoksa bileşenler yok sayılır.

Sık Sorulan Sorular

Butona basınca "Etkileşim başarısız oldu" çıkıyor, neden?

Butonun custom_id'sini dinleyen bir kod yok, collector süresi dolmuş ya da yanıt 3 saniyeyi geçiyor. Link butonları ise zaten interaction göndermez.

custom_id'ye ne kadar veri koyabilirim?

En fazla 100 karakter. Kullanıcı ID'si gibi kısa durum bilgileri sığar; daha büyük veriler için bir anahtar koyup asıl veriyi SQLite ya da Redis gibi bir depoda tutun.

Modal'da kaç alan olabilir?

Modal en fazla 5 üst düzey bileşen alır. discord.js rehberine göre bunların her biri bir Label ya da Text Display olabilir.

Modal'a select menu koyabilir miyim?

Evet. String, user, role, mentionable ve channel select menüleri modal içinde bir Label'ın içine konarak kullanılabilir. Modalda required alanı geçerlidir, mesajlarda yok sayılır.

Bileşenli mesaja embed de ekleyebilir miyim?

Klasik bileşenlerde evet, content ve embeds ile birlikte kullanılabilir. Components V2 bayrağı kullanıyorsanız hayır; o modda metin ve görseller bileşenlerle verilir. Embed tarafı için Discord embed mesaj oluşturma yazısına bakın.

Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.

İlgili içerikler: Slash komut oluşturma · Etkileşim başarısız oldu hatası · Components V2 nedir · Embed mesaj oluşturma · Premium abonelik · Discord webhook ve bot entegrasyonu