Episode ini membahas cara komponen Svelte berkomunikasi: props untuk data dari parent ke child, event dispatch untuk child ke parent, slot untuk injeksi konten, two-way binding dengan bind, serta pola komposisi komponen yang reusable dan mudah dipelihara.

Aplikasi nyata tidak pernah berupa satu komponen raksasa. Kalian memecah tampilan menjadi komponen kecil yang masing-masing punya satu tanggung jawab, lalu menyusunnya seperti balok LEGO. Yang menentukan kualitas arsitektur bukan ukuran komponen, melainkan cara komponen saling berbicara.
Svelte menawarkan tiga kanal komunikasi yang jelas: props mengalir ke bawah dari parent ke child, event dispatch mengalir ke atas dari child ke parent, dan slot menyuntikkan konten dari luar. Ditambah bind: untuk binding dua arah, kalian bisa membangun hierarki komponen yang rapi tanpa state global yang berantakan.
Episode ini membahas keempat mekanisme tersebut, lengkap dengan contoh nyata. Kalian juga akan belajar pola komposisi yang membuat komponen benar-benar reusable — tidak hanya untuk proyek ini, tapi untuk seluruh karier kalian sebagai developer Svelte.
Di Svelte 5, props dideklarasikan dengan rune $props. Child menerima nilai dari parent melalui atribut:
<script>
let { nama, umur } = $props()
</script>
<p>{nama} berumur {umur} tahun</p>let { nama, umur } = $props() menandai nama dan umur sebagai props yang bisa dikirim parent. Di Svelte 4, sintaksnya export let nama. Keduanya valid, tapi $props memberi dukungan TypeScript yang lebih baik.
Parent memakai komponen child dengan atribut sesuai nama prop:
<script>
import Pengguna from "./Pengguna.svelte"
</script>
<Pengguna nama="Arman" umur={28} />nama="Arman" mengirim string literal, sedangkan umur={28} mengirim ekspresi. Props membantu memisahkan data dari tampilan: komponen Pengguna tidak peduli dari mana data berasal, ia hanya menerima dan merender.
Untuk mengirim pesan ke parent, child memakai createEventDispatcher dari svelte:
<script>
import { createEventDispatcher } from "svelte"
const dispatch = createEventDispatcher()
function pilih() {
dispatch("pilih", { id: 42 })
}
</script>
<button onclick={pilih}>Pilih item</button>dispatch("pilih", { id: 42 }) mengirim event bernama pilih dengan payload object. Parent menangkap event ini tanpa perlu berbagi state — child tetap independen.
Parent mendengarkan event dengan atribut yang sama dengan nama event:
<script>
import Item from "./Item.svelte"
function handlePilih(event) {
console.log("Dipilih:", event.detail.id)
}
</script>
<Item onpilih={handlePilih} />onpilih={handlePilih} mendengarkan event pilih. Payload yang dikirim dispatch tersedia di event.detail. Pola ini menjaga aliran data satu arah: parent memberi data lewat props, child memberi kabar lewat event.
Slot memungkinkan parent menaruh markup di dalam komponen child:
<div class="kartu">
<slot />
</div><slot /> adalah titik tempat konten parent dirender. Komponen menjadi wadah yang dapat diisi ulang — pola yang dipakai library seperti modals, accordion, dan card. Tanpa slot, kalian terpaksa menulis banyak props untuk setiap bagian kecil tampilan.
Untuk beberapa area konten, gunakan named slot. Slot juga bisa mengirim data balik ke parent:
<div class="kartu">
<header><slot name="judul">Judul default</slot></header>
<main><slot konten={{ item: "data" }} /></main>
</div><slot name="judul"> mendefinisikan slot bernama yang diisi parent dengan atribut slot="judul". Slot props seperti konten={{ item: "data" }} mengirim data dari child ke parent — kebalikan arah dari biasanya, berguna untuk layout yang fleksibel.
Property binding yang kalian kenal di episode 4 bisa dipakai antar komponen dengan sintaks bind:prop:
<script>
let { nilai } = $props()
</script>
<input bind:value={nilai} /><script>
import SliderNilai from "./SliderNilai.svelte"
let nilai = $state(50)
</script>
<SliderNilai bind:nilai />bind:nilai membuat prop nilai dua arah: perubahan di input child memperbarui nilai di parent, dan sebaliknya. Ini adalah alternatif ergonomis untuk pola dispatch saat parent dan child benar-benar berbagi satu nilai.
Gunakan bind: ketika state memang satu kesatuan dengan child — input, slider, toggle. Gunakan event dispatch ketika child hanya memberi tahu kejadian, sementara keputusan dan state tetap di parent. Prinsipnya: jangan mengikat apa pun yang bisa diteruskan sebagai satu arah.
Salah satu pola paling efektif: komponen presentational hanya merender props, sedangkan komponen container mengelola state dan logika. Contoh kombinasi semua mekanisme:
<script>
import Tombol from "./Tombol.svelte"
let klik = $state(0)
</script>
<Tombol onklik={() => (klik += 1)}>
Klik saya {klik} kali
</Tombol>Komponen Tombol menerima slot untuk label dan mengirim event klik. Parent mengelola state klik. Hasilnya: Tombol bisa dipakai di mana saja tanpa tahu konteksnya, dan parent tetap memegang kendali penuh atas data.
Beberapa pedoman yang menjaga komponen tetap bersih:
Inti yang harus dibawa pulang:
$props mengirim data dari parent ke child, lengkap dengan default.createEventDispatcher dan dispatch mengirim event dari child ke parent.bind:prop membuat komunikasi dua arah antar komponen yang berbagi satu nilai.bind untuk nilai bersama dan event untuk pemberitahuan kejadian.Di episode 6 selanjutnya kita akan membahas stores dan state management — writable, readable, dan derived stores, custom stores, subscription, serta pola state management untuk aplikasi kecil dan menengah. Komunikasi komponen yang kalian kuasai hari ini akan melengkapi store yang menjadi tema utama episode berikutnya.