Slots — Vue

Default Slot ---template--- Penggunaan di parent: Konten di sini Named Slots ---template--- Judul Konten utama Footer

Slot adalah lubang di template child yang diisi parent dengan markup. Props mengirim data, seperti teks dan angka. Slot mengirim potongan template utuh: judul, paragraf, tombol. Bayangin nampan saji Warung Bu Sri yang punya sekat-sekat berlabel "judul", "isi", dan "aksi". Bentuk nampannya selalu sama, tapi yang menaruh makanan di tiap sekat adalah yang menyajikan. Sekat yang dibiarkan kosong menampilkan kertas cadangan, misalnya "Menu belum diisi". Nampan itu komponen child Kartu, sekatnya slot, dan yang menyajikan parent-nya.

🧪 Tebakan cepat: Kartu punya <slot name="judul"> dan <slot>. Parent menulis <h3>Nasi Goreng</h3> langsung di antara <Kartu> dan </Kartu>, tanpa <template #judul>. Judulnya masuk slot yang mana? Tebak dulu, jawabannya ada di bagian "Named slot: banyak lubang".

Default slot: satu lubang

<!-- Kartu.vue -->
<template>
  <div class="kartu">
    <slot></slot>
  </div>
</template>
<!-- App.vue -->
<Kartu>
  <h3>Nasi Goreng</h3>
  <p>Rp15000</p>
</Kartu>

HTML yang keluar:

<div class="kartu"><h3>Nasi Goreng</h3><p>Rp15000</p></div>

Fallback content: isi cadangan

<!-- Kartu.vue -->
<div class="kartu">
  <slot>Menu belum diisi</slot>
</div>
Parent menulis Yang tampil
<Kartu><p>Es Teh</p></Kartu> Es Teh
<Kartu /> Menu belum diisi

Isi di antara <slot> dan </slot> disebut fallback content. Dia cuma tampil kalau parent gak mengirim apa-apa. Child dengan <slot>Default</slot> yang gak diisi menampilkan Default.

Named slot: banyak lubang

<!-- Kartu.vue -->
<template>
  <div class="kartu">
    <header><slot name="judul">Tanpa judul</slot></header>
    <main><slot></slot></main>
    <footer><slot name="aksi"></slot></footer>
  </div>
</template>
<!-- App.vue -->
<Kartu>
  <template #judul><h3>Nasi Goreng</h3></template>
  <p>Rp15000</p>
  <template #aksi><button>Tambah</button></template>
</Kartu>

HTML yang keluar:

<div class="kartu">
  <header><h3>Nasi Goreng</h3></header>
  <main><p>Rp15000</p></main>
  <footer><button>Tambah</button></footer>
</div>

📌 Scoped slot: child meminjamkan data

Kadang child yang punya datanya, tapi parent yang mau menentukan tampilannya. Child mengirim data lewat atribut di <slot>:

<!-- DaftarMenu.vue -->
<script setup>
const menu = [
  { nama: "Nasi Goreng", harga: 15000 },
  { nama: "Mie Ayam", harga: 12000 },
  { nama: "Es Teh", harga: 5000 },
]
</script>

<template>
  <ul>
    <li v-for="m in menu" :key="m.nama">
      <slot :item="m">{{ m.nama }}</slot>
    </li>
  </ul>
</template>
<!-- App.vue -->
<DaftarMenu v-slot="{ item }">
  <b>{{ item.nama }}</b> Rp{{ item.harga }}
</DaftarMenu>

Hasilnya tiga <li>: Nasi Goreng Rp15000, Mie Ayam Rp12000, Es Teh Rp5000. v-slot="{ item }" mengambil item yang dikirim child. Untuk slot bernama: <template #baris="{ item }">.

File .vue dan editor latihan

Di editor, child ditulis sebagai objek dan dipasang dengan <component :is>. Isi slot ditulis di antara <component> dan </component>:

const Kartu = {
  template: `
    <div class="kartu">
      <header><slot name="judul">Tanpa judul</slot></header>
      <main><slot>Menu belum diisi</slot></main>
    </div>
  `,
}

---template---
<div>
  <component :is="Kartu">
    <template #judul><h3>Nasi Goreng</h3></template>
    <p>Rp15000</p>
  </component>
  <component :is="Kartu" />
</div>
Di file .vue Di editor latihan
<slot> di <template> milik Kartu.vue <slot> di opsi template objek Kartu
<Kartu>...</Kartu> <component :is="Kartu">...</component>

Kedua latihannya memakai bentuk ini. Pemeriksanya membaca HTML hasilnya (.card p berisi Konten kartu, lalu .panel-header berisi Profil dan .panel-body berisi Data pengguna) dan juga <slot> di template child, <template #header> di parent, dan bahwa <div> kartu dan panelnya ditulis di template child.

⚠️ Jebakan yang sering ketemu

TL;DR: Slot adalah lubang di template child yang diisi parent dengan markup. <slot /> adalah default slot, isi di antara tag komponen mendarat di sana. Isi di antara <slot> dan </slot> adalah fallback content yang tampil kalau parent gak mengisi apa-apa. <slot name="judul"> membuat named slot yang diisi dengan <template #judul> (singkatan v-slot:judul); isi tanpa <template #...> masuk default slot. Isi slot membaca data parent, dan scoped slot (<slot :item="m"> dengan v-slot="{ item }") meminjamkan data child ke parent.

Yang akan kamu pelajari