
JavaScript'te event'ler tetiklendiğinde, sadece tıkladığınız veya etkileşimde bulunduğunuz elementte kalmaz. Olay, DOM ağacında yukarı doğru yayılır. Bu davranışa Event Bubbling (Olay Kabarcıklanması) denir. Bu kavramı anlamak, karmaşık web uygulamalarında beklenmedik davranışlarla karşılaşmamak için kritik öneme sahiptir.
Event Bubbling Nedir?
Bir elemente tıkladığınızda, o event önce tıklanan elementte, sonra onun parent (üst) elementinde, sonra onun da parent'ında... böyle devam ederek en üste (document ve window) kadar yayılır.
Görsel Temsil
window
└── document
└── <html>
└── <body>
└── <div class="container">
└── <button>Tıkla</button> ← Tıklama burada başlar
↑
↑ Event yukarı doğru "kabarcık" gibi yükselir
↑Basit Örnek
<div id="buyuk-kutu" style="padding: 50px; background: lightblue;">
Büyük Kutu
<div id="orta-kutu" style="padding: 30px; background: lightgreen;">
Orta Kutu
<button id="buton">Tıkla Beni</button>
</div>
</div>const buyukKutu = document.querySelector('#buyuk-kutu');
const ortaKutu = document.querySelector('#orta-kutu');
const buton = document.querySelector('#buton');
buyukKutu.addEventListener('click', function() {
console.log('Büyük kutu tıklandı!');
});
ortaKutu.addEventListener('click', function() {
console.log('Orta kutu tıklandı!');
});
buton.addEventListener('click', function() {
console.log('Buton tıklandı!');
});Butona tıkladığınızda konsol çıktısı:
Buton tıklandı!
Orta kutu tıklandı!
Büyük kutu tıklandı!Gördüğünüz gibi, sadece butona tıklasak bile, üç event handler da çalıştı! Çünkü event yukarı doğru bubble etti (kabarcıklandı).
Gerçek Hayat Problemi: Modal Kapatma
Bir modal (açılır pencere) düşünün:
<div id="modal-arkaplan" class="modal-arkaplan">
<div id="modal-icerik" class="modal-icerik">
<h2>Modal Başlık</h2>
<p>Modal içeriği burada...</p>
<button id="kapat-btn">Kapat</button>
</div>
</div>const arkaplan = document.querySelector('#modal-arkaplan');
const icerik = document.querySelector('#modal-icerik');
const kapatBtn = document.querySelector('#kapat-btn');
// Arka plana tıklanınca modal kapansın
arkaplan.addEventListener('click', function() {
this.style.display = 'none';
console.log('Modal kapandı - arkaplan tıklandı');
});
// Kapat butonuna tıklanınca modal kapansın
kapatBtn.addEventListener('click', function() {
arkaplan.style.display = 'none';
console.log('Modal kapandı - buton tıklandı');
});Problem: Kapat butonuna tıkladığınızda iki kez "kapandı" mesajı görürsünüz! Çünkü:
- Önce buton click handler'ı çalışır
- Event bubble eder ve arkaplan click handler'ı da çalışır
Bu spesifik örnekte büyük bir sorun değil, ama bazen istenmeyen davranışlara yol açabilir.
stopPropagation(): Bubbling'i Durdurma
event.stopPropagation() metodu, event'in daha fazla yukarı yayılmasını engeller.
kapatBtn.addEventListener('click', function(event) {
event.stopPropagation(); // Bubbling'i durdur!
arkaplan.style.display = 'none';
console.log('Modal kapandı - buton tıklandı');
});Artık butona tıkladığınızda, event arkaplan'a kadar ulaşmaz.
Gerçek Hayat Örneği: Dropdown Menü
<div class="dropdown">
<button class="dropdown-btn">Menü ▼</button>
<div class="dropdown-icerik">
<a href="#">Profil</a>
<a href="#">Ayarlar</a>
<a href="#">Çıkış</a>
</div>
</div>const dropdown = document.querySelector('.dropdown');
const dropdownBtn = document.querySelector('.dropdown-btn');
const dropdownIcerik = document.querySelector('.dropdown-icerik');
// Butona tıklanınca menüyü aç/kapat
dropdownBtn.addEventListener('click', function(event) {
event.stopPropagation(); // Bubbling'i durdur
dropdownIcerik.classList.toggle('goster');
});
// Menü içine tıklanınca kapanmasın
dropdownIcerik.addEventListener('click', function(event) {
event.stopPropagation(); // Bubbling'i durdur
});
// Sayfanın herhangi bir yerine tıklanınca menüyü kapat
document.addEventListener('click', function() {
dropdownIcerik.classList.remove('goster');
});Bu pattern neden çalışır?
- Butona tıklandığında menü açılır, ama
stopPropagationsayesinde document'a ulaşmaz - Menü içine tıklandığında da document'a ulaşmaz
- Sayfanın başka bir yerine tıklandığında menü kapanır
Gerçek Hayat Örneği: Silme Butonu Olan Kart
<div class="kart" data-id="1">
<h3>Ürün Adı</h3>
<p>Ürün açıklaması...</p>
<button class="sil-btn">Sil</button>
</div>const kartlar = document.querySelectorAll('.kart');
kartlar.forEach(function(kart) {
// Karta tıklanınca detay sayfasına git
kart.addEventListener('click', function() {
const id = this.dataset.id;
window.location.href = `/urun/${id}`;
});
// Sil butonuna tıklanınca ürünü sil (sayfaya gitme!)
const silBtn = kart.querySelector('.sil-btn');
silBtn.addEventListener('click', function(event) {
event.stopPropagation(); // Kart click'ini tetikleme!
if (confirm('Silmek istediğinizden emin misiniz?')) {
kart.remove();
}
});
});Eğer stopPropagation() kullanmasaydık, sil butonuna tıkladığımızda hem silme işlemi yapılır hem de ürün detay sayfasına yönlendirilirdik!
event.target vs event.currentTarget
Bubbling'i anlamak için bu iki özelliği bilmek gerekir:
| Özellik | Açıklama |
|---|---|
event.target | Olayı başlatan element (tıklanan) |
event.currentTarget | Handler'ın bağlı olduğu element |
buyukKutu.addEventListener('click', function(event) {
console.log('target:', event.target); // Tıklanan element
console.log('currentTarget:', event.currentTarget); // buyukKutu
});Butona tıkladığınızda:
event.target→<button>(tıklanan)event.currentTarget→<div id="buyuk-kutu">(handler'ın bağlı olduğu)
Gerçek Hayat Örneği: Tablo Satır Tıklama
<table id="kullanici-tablosu">
<tr data-id="1">
<td>Ahmet</td>
<td>ahmet@email.com</td>
<td><button class="duzenle">Düzenle</button></td>
</tr>
<tr data-id="2">
<td>Mehmet</td>
<td>mehmet@email.com</td>
<td><button class="duzenle">Düzenle</button></td>
</tr>
</table>const tablo = document.querySelector('#kullanici-tablosu');
tablo.addEventListener('click', function(event) {
// Düzenle butonuna mı tıklandı?
if (event.target.classList.contains('duzenle')) {
const satir = event.target.closest('tr');
const id = satir.dataset.id;
console.log('Düzenleniyor:', id);
return;
}
// Satırın herhangi bir yerine tıklandı
const satir = event.target.closest('tr');
if (satir) {
const id = satir.dataset.id;
console.log('Satır seçildi:', id);
// Seçili satırı vurgula
document.querySelectorAll('tr').forEach(s => s.classList.remove('secili'));
satir.classList.add('secili');
}
});stopPropagation vs preventDefault
Bu iki metod sıkça karıştırılır:
| Metod | Ne Yapar |
|---|---|
stopPropagation() | Event'in yukarı yayılmasını (bubbling) durdurur |
preventDefault() | Tarayıcının varsayılan davranışını engeller |
// Örnek: Bir link içindeki buton
const link = document.querySelector('a');
const butonIcinde = link.querySelector('button');
butonIcinde.addEventListener('click', function(event) {
event.stopPropagation(); // Link'in click handler'ını tetikleme
event.preventDefault(); // Sayfaya gitmeyi engelle (link davranışı)
console.log('Buton tıklandı, ama link çalışmadı');
});Ne Zaman stopPropagation Kullanmalı?
✅ Kullanın:
- Modal içindeki butonlar
- Dropdown menüler
- İç içe tıklanabilir elementler
- Silme/düzenleme butonları olan kartlar
❌ Dikkatli olun:
- Çok fazla kullanmak debugging'i zorlaştırır
- Analytics event'lerini engelleyebilir
- Üst düzey event listener'ları çalışmaz
Özet
Bu makalede öğrendiklerimiz:
✅ Event bubbling: Olaylar DOM ağacında yukarı doğru yayılır
✅ event.stopPropagation() ile bubbling durdurulabilir
✅ event.target tıklanan elementi, event.currentTarget handler'ın bağlı olduğu elementi gösterir
✅ Modal, dropdown ve tıklanabilir kartlarda bubbling kontrolü önemlidir
✅ stopPropagation ve preventDefault farklı amaçlara hizmet eder
Bir sonraki makalede Event Delegation (Olay Delegasyonu) konusunu inceleyeceğiz - bubbling'in güçlü bir kullanım şekli!


