HTML <template> öğesi, sayfada hemen gösterilmeyen HTML parçalarını saklamak için kullanılır; <slot> öğesi ise bir web bileşeninin içinde, bileşeni kullanan kişinin kendi işaretlemesiyle dolduracağı yer tutucudur. Kısa cevap şudur: tekrar tekrar kopyalayacağınız bir yapıyı (örneğin bir tablo satırı ya da kart) <template> içine yazarsınız, JavaScript ile kopyasını alıp sayfaya eklersiniz. shadowrootmode özniteliği verirseniz aynı öğe, JavaScript olmadan, üst öğesine bir shadow DOM ağacı ekler ve içindeki <slot> öğeleri dışarıdan gelen içeriği gösterir.

Bu yazıda şablon içeriğinin neden görünmediğini, content özelliğini, bildirimsel shadow DOM özniteliklerini, adlı ve adsız slotları, slot, part ve exportparts global özniteliklerini ve deneysel <template for> kullanımını MDN belgelerine göre anlatıyoruz. Bileşen kodunun JavaScript tarafı için JavaScript öğrenme rehberine bakabilirsiniz.

template içeriği neden ekranda görünmez?

Tarayıcı <template> içindeki işaretlemeyi ayrıştırır ama göstermez. MDN teknik özetinde öğenin izin verilen içeriği "hiçbir şey" olarak yazılıdır; bunun nedeni, kaynakta öğenin içine yazdıklarınızın aslında öğenin çocukları olmamasıdır. childNodes özelliği her zaman boştur. İçerik, salt okunur content özelliğindeki bir DocumentFragment nesnesinde tutulur; bu özelliğin HTML tarafında bir öznitelik karşılığı yoktur.

Ayrıştırma biçiminin bir sonucu daha vardır: şablon içinde yazılan <html>, <head> ve <body> açılış ve kapanış etiketleri sözdizimi hatası sayılır ve yok sayılır. Yani <template><head><title>Test</title></head></template> yazmak, <template><title>Test</title></template> yazmakla aynıdır.

template öğesinin üç kullanım yolu

template öğesinin üç kullanım yolu: Şablon parçası, Bildirimsel shadow DOM, Sıra dışı yama (out-of-order patching)
  • Şablon parçası: İçerik gösterilmez; JavaScript ile kopyalanıp sayfaya eklenir. En yaygın kullanım budur.
  • Bildirimsel shadow DOM: shadowrootmode özniteliği varsa ayrıştırıcı şablonu hemen bir shadow root ile değiştirir ve üst öğeye bağlar.
  • Sıra dışı yama (out-of-order patching): <template for="..."> içeriği, sayfada önceden konmuş bir işaretçinin yerine yerleştirilir. MDN bu kullanımı deneysel ve sınırlı destekli olarak işaretler.

Örnek: tablo satırlarını şablondan üretmek

MDN örneğindeki fikir şudur: tablo HTML içinde boş bir <tbody> ile hazırdır; tek bir satırın yapısı ise ayrı bir şablonda durur. Betik her yeni kayıt için şablonu kopyalar, hücreleri doldurur ve satırı tabloya ekler. Tablo etiketlerinin kendisi tablo yazısında anlatılıyor.

html
<table id="urunler">
  <thead>
    <tr>
      <th>Kod</th>
      <th>Ürün</th>
    </tr>
  </thead>
  <tbody>
    <!-- satırlar betikle eklenecek -->
  </tbody>
</table>

<template id="urun-satiri">
  <tr>
    <td class="kod"></td>
    <td></td>
  </tr>
</template>
javascript
const tbody = document.querySelector("#urunler tbody");
const sablon = document.querySelector("#urun-satiri");

const kopya = document.importNode(sablon.content, true);
const hucreler = kopya.querySelectorAll("td");
hucreler[0].textContent = "1001";
hucreler[1].textContent = "Kablosuz klavye";
tbody.appendChild(kopya);

Kopyalamak için MDN document.importNode() yöntemini önerir. cloneNode() de bir kopya üretir, fark belge bağlamındadır: importNode() kopyayı çağıran belgenin bağlamında, cloneNode() ise kopyalanan düğümün belgesinde oluşturur. Bu bağlam özel öğelerin hangi tanım kaydıyla (CustomElementRegistry) oluşturulacağını belirlediği için, şablondaki özel öğelerin geçerli belgedeki tanımlarla kurulması isteniyorsa importNode() doğru tercihtir.

Olay dinleyicisini parçaya değil, çocuğa ekleyin

appendChild() bir DocumentFragment aldığında parçanın kendisini değil, yalnızca çocuk düğümlerini hedefe taşır. Bu yüzden kopyalanan parçaya eklenen bir click dinleyicisi sayfaya geçmez. MDN örneğinde ilk kopyada dinleyici parçaya eklendiği için tıklama çalışmaz; ikinci kopyada dinleyici children[0] öğesine eklendiği için beklenen sonuç alınır. Kural: veri ve dinleyicileri parçanın kendisine değil, içindeki öğelere bağlayın.

Bildirimsel shadow DOM: shadowrootmode

Bildirimsel shadow DOM: shadowrootmode: shadowrootclonable, shadowrootdelegatesfocus, shadowrootserializable, shadowrootslotassignment

shadowrootmode özniteliği, Element.attachShadow() yönteminin HTML ile yazılan karşılığıdır ve şablonun üst öğesine bir shadow root ekler. İki geçerli değeri vardır: open iç yapıyı JavaScript erişimine açar ve MDN çoğu kullanım için bunu önerir; closed iç yapıyı JavaScript'ten gizler.

html
<article>
  <style>
    p { padding: 8px; }
  </style>
  <p>Bu paragraf normal DOM içinde.</p>
</article>
<article>
  <template shadowrootmode="open">
    <style>
      p { padding: 8px; }
    </style>
    <p>Bu paragraf shadow DOM içinde.</p>
  </template>
</article>

MDN örneğinde ilk <style> bütün belgeye uygulanırken, ikinci <style> yalnızca şablonun yerine oluşan shadow root içinde geçerlidir. Bu kapsam ayrımı, bileşenlerin stillerinin sayfanın geri kalanına sızmamasını sağlar. Stil kurallarının kendisi CSS konusudur.

Dikkat edilmesi gereken kurallar şunlardır. Ayrıştırıcı bir ShadowRoot nesnesini yalnızca bir üst öğe içindeki geçerli değerli ilk şablon için oluşturur. Öznitelik yoksa, geçersiz bir değer taşıyorsa ya da aynı üst öğede zaten bildirimsel bir shadow root oluşturulmuşsa normal bir HTMLTemplateElement oluşur. Ayrıştırma bittikten sonra shadowRootMode özelliğini değiştirmek, var olan şablonu shadow root'a çevirmez. Eski örneklerde görebileceğiniz standart dışı shadowroot özniteliği kaldırılmıştır; yerine standart shadowrootmode kullanılır.

shadowroot ile başlayan diğer öznitelikler

ÖznitelikNe yapar
shadowrootclonableShadow root için clonable değerini true yapar; üst öğe cloneNode() ya da importNode() ile kopyalanınca shadow root da kopyalanır.
shadowrootdelegatesfocusOdaklanamayan bir iç öğe seçilince odak ağaçtaki ilk odaklanabilir öğeye aktarılır. Varsayılan false.
shadowrootserializableserializable değerini true yapar; getHTML() serializableShadowRoots seçeneğiyle çağrılırsa shadow root da metne dökülür. Varsayılan false.
shadowrootslotassignmentSlot atamasını belirler: named (varsayılan) ya da manual.
shadowrootcustomelementregistryShadow root için özel öğe kaydını belge kaydı yerine null yapar; kapsamlı bir kayıt sonradan bağlanabilir.
shadowrootreferencetargetDışarıdan ana öğeye yapılan kimlik başvurularının shadow DOM içindeki hangi öğeye yönleneceğini belirtir.

shadowrootdelegatesfocus etkisini MDN şöyle gösterir: öznitelik olmayan bileşende, içerideki düz metne tıklamak odağı değiştirmez; öznitelik olan bileşende aynı tıklama odağı içerideki ilk <input> öğesine taşır ve ana öğe de odaklanmış sayılır. Klavye erişimiyle ilgili genel kurallar tabindex yazısında. Tablodaki daha yeni öznitelikler için tarayıcı desteği için MDN uyumluluk tablosuna bakın.

slot öğesi: bileşenin doldurulabilir yerleri

<slot>, bir web bileşeninin içinde bileşeni kullanan kişinin kendi içeriğiyle dolduracağı yer tutucudur. Slotlar düz metin, HTML öğeleri ya da başka web bileşenleri alabilir. Slotun içine yazılan içerik varsayılan içeriktir ve slota başka içerik atanmazsa gösterilir. MDN teknik özetine göre öğenin içerik modeli saydamdır (transparent), ifade içeriği kabul eden her öğenin içinde yer alabilir ve içeriği değiştiğinde slotchange olayı tetiklenir.

name özniteliği olan slot adlı slottur; olmayan slotun adı boş metin kabul edilir. Adlı atama kullanan bir shadow root'ta, ana öğenin üst düzey çocuklarından slot özniteliği taşıyanlar aynı adlı slota yerleşir. Özniteliği olmayan çocukların hepsi ilk adsız slota, yani varsayılan slota gider. Aynı adı taşıyan iki slot varsa eşleşen öğelerin tümü ilk slotta gösterilir; bu yüzden slot adları her shadow root içinde benzersiz olmalıdır. Manuel atama kullanılıyorsa name özniteliğinin etkisi yoktur.

html
<article id="kart">
  <template shadowrootmode="open">
    <h2><slot name="baslik">Başlıksız</slot></h2>
    <div class="bilgi"><slot name="bilgi"></slot></div>
    <div class="govde"><slot></slot></div>
  </template>

  <p>Bu paragrafın slot özniteliği yok, varsayılan slota gider.</p>
  <span slot="baslik">Yeni kampanya</span>
  <span slot="bilgi">7 Kasım 2026</span>
  <p>Bu paragraf da varsayılan slota gider.</p>
</article>

Bu örnekte iki <span> öğesi slot özniteliğindeki adla eşleşen yerlere yerleşir, iki <p> öğesi ise kaynak sırasıyla adsız slotta gösterilir. baslik adlı slota içerik verilmeseydi "Başlıksız" varsayılan metni görünürdü. shadowrootslotassignment yazmadık; adlı atama zaten varsayılandır.

Manuel slot ataması

shadowrootslotassignment="manual" verildiğinde otomatik atama yapılmaz; her öğe JavaScript ile HTMLSlotElement.assign() çağrılarak bir slota atanır, atanmayan slot boş kalır. MDN, bir düğümün belirli bir slota yalnızca bir kez atanabileceğini ve assign() yöntemine birden çok düğüm verildiğinde sıranın belirleyici olduğunu not eder. Ayrıca MDN uyarır: öznitelik desteklenmezse tarayıcı adlı atamaya döner ve örnekteki adsız öğelerin hepsi ilk adsız slota yerleşir.

slot, part ve exportparts global öznitelikleri

slot global özniteliği, bir öğeyi shadow ağacındaki aynı adlı <slot> öğesine atar. Birden çok öğe aynı slot adını taşıyabilir; özniteliği olmayan öğeler varsa adsız slota atanır.

part global özniteliği, boşlukla ayrılmış parça adları listesi alır ve shadow ağacındaki bir öğenin CSS tarafında ::part() sözde öğesiyle dışarıdan seçilebilmesini sağlar. Shadow ağacı, normal DOM'daki seçici ve sorguların erişemediği yalıtılmış bir yapı olduğu için bu kapı gereklidir. Ancak ::part() yalnızca doğrudan üst DOM'a görünür; iç içe bileşenlerde daha dıştaki atalar parçaları göremez.

exportparts bu sınırı aşar. Shadow ağacının bağlı olduğu ana öğeye (shadow host) yazılır ve virgülle ayrılmış parça adlarını dışarı aktarır. Her madde aslında bir eşlemedir: exportparts="baslik", exportparts="baslik:baslik" ile aynıdır; baslik:dis-baslik yazarsanız parça dışarıda farklı bir adla görünür.

html
<template id="kart-sablonu">
  <div part="taban">
    <div part="ust"><slot name="ust"></slot></div>
    <div part="govde"><slot name="govde"></slot></div>
  </div>
</template>

<template id="kart-sarmalayici">
  <kart-bileseni exportparts="taban, ust:kart-ust"></kart-bileseni>
</template>

Buradaki <kart-bileseni> özel bir öğedir ve MDN örneğinde olduğu gibi customElements.define() ile JavaScript tarafında tanımlanması gerekir. Dış sayfa artık taban parçasını aynı adla, ust parçasını ise kart-ust adıyla ::part() üzerinden seçebilir; govde dışa aktarılmadığı için sarmalayıcının dışından ulaşılamaz.

template for ile sıra dışı yama (deneysel)

HTML normalde yukarıdan aşağı teslim edilir ve gösterilir. MDN'nin anlattığı yeni kullanımda sayfaya bir işleme talimatı (processing instruction) işaretçisi konur, örneğin <?marker name="fiyat">; sayfanın çok daha aşağısında gelen <template for="fiyat"> öğesinin içeriği bu işaretçinin yerine yerleştirilir. <?start name="..."> ile <?end> çifti arasına "Yükleniyor..." gibi geçici bir içerik koymak da mümkündür; şablon işlendiğinde bu bölümün tamamı değiştirilir.

Kurallar şöyledir: for değeri hiçbir işaretçiyle eşleşmezse şablon içeriği gizli kalır. Bir <template for> yalnızca kendi üst öğesinin DOM ağacındaki işaretçileri değiştirebilir; tek istisna <body> öğesinin doğrudan çocuğu olan şablonlardır, bunlar <head> içindeki işaretçileri de güncelleyebilir. MDN bu kullanımın deneysel olduğunu ve sınırlı desteklendiğini belirtir; tarayıcı desteği için MDN uyumluluk tablosuna bakın.

template nereye yazılabilir?

Teknik özete göre <template> üst veri içeriği, akış içeriği, ifade içeriği ve betik destekleyen öğe kategorilerindedir. Bu sayede <head> içinde ya da paragraf gibi ifade içeriği kabul eden öğelerin içinde kullanılabilir; span özniteliği olmayan bir <colgroup> öğesinin çocuğu da olabilir. Her iki etiket de zorunludur. Öğenin örtük ARIA rolü yoktur ve role verilmesine izin verilmez; aynı kural <slot> için de geçerlidir. Kategorilerin ayrıntısı MDN: içerik kategorileri sayfasında.

Sık yapılan hatalar

Sık yapılan hatalar: Şablon içeriğine template.querySelector() ya da childNodes ile ulaşmaya..., Kopyalamadan doğrudan template.content parçasını eklemek. Parça eklendiğinde...
  • Şablon içeriğine template.querySelector() ya da childNodes ile ulaşmaya çalışmak. İçerik template.content içindedir.
  • Kopyalamadan doğrudan template.content parçasını eklemek. Parça eklendiğinde çocukları taşınır ve şablon ikinci kullanımda boş kalır; her kullanımda yeni bir kopya alın.
  • Olay dinleyicisini DocumentFragment nesnesine bağlamak; dinleyici sayfaya taşınmaz.
  • Aynı üst öğede iki bildirimsel shadow root beklemek. Yalnızca ilk şablon shadow root olur.
  • Aynı adda iki slot tanımlamak. Eşleşen içeriğin tamamı ilk slotta görünür.
  • İç içe bileşende exportparts yazmadan dış sayfadan ::part() ile iç parçaya ulaşmayı beklemek.

Sık Sorulan Sorular

template ile hidden özniteliği arasındaki fark nedir?

hidden ile gizlenen öğe DOM'un normal parçasıdır; içindeki betikler çalışır, form alanları gönderilir. <template> içeriği ise öğenin çocuğu bile değildir, content içinde bekleyen bir parçadır ve kopyalanıp eklenene kadar sayfanın etkin bir bölümü olmaz.

Bildirimsel shadow DOM için JavaScript gerekir mi?

Shadow root'un oluşması için gerekmez; shadowrootmode özniteliğini ayrıştırıcı işler. Manuel slot ataması ya da bileşen davranışı gibi işler için JavaScript gerekir. Tarayıcı desteği için MDN uyumluluk tablosuna bakın.

slot öğesini shadow DOM dışında kullanabilir miyim?

MDN örneğinde belirtildiği gibi slotlar yalnızca şablon bir shadow root içinde kullanıldığında slot olarak çalışır. Normal belgede <slot> yazmak bir yer tutucu işlevi görmez.

template öğesini head içinde kullanabilir miyim?

Evet. Teknik özete göre <template> üst veri içeriği kategorisindedir ve üst veri içeriği kabul eden öğelerin, yani <head> öğesinin içinde yer alabilir. İçeriği yine gösterilmez ve content özelliğinden okunur.

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: HTML öğrenme rehberi · global öznitelikler · hidden ve inert · HTML tablo · script etiketi · yeni HTML özellikleri · JavaScript öğrenme rehberi