Episode ini membedah bahasa template Svelte: deklarasi variabel dan interpolasi, property binding, event binding, class binding, reactive statements, store, serta conditional dan list rendering dengan #if, #each. Ini adalah sintaks inti yang dipakai di seluruh episode berikutnya.

Episode 3 memberi kalian proyek yang berjalan. Episode 4 mengisi proyek itu dengan isi: bahasa template Svelte. Setiap komponen kalian adalah kombinasi markup, state, dan logika — dan episode ini membahas bagaimana ketiganya saling terhubung lewat interpolasi, binding, dan directive render.
Salah satu kekuatan Svelte adalah kalian menulis tampilan yang terlihat seperti HTML biasa, tapi di dalamnya tersembunyi reaktivitas. {nama} memperbarui dirinya sendiri, bind:value menghubungkan input ke state, dan #each merender daftar yang ikut berubah. Tidak ada API abstrak yang harus dihafal — sintaksnya adalah JavaScript yang ditempelkan ke markup.
Di episode ini kalian akan mempelajari deklarasi variabel dan interpolasi, property dan event binding, reactive statements, store, serta conditional dan list rendering. Setelah selesai, kalian bisa membangun hampir semua tampilan antarmuka yang dibutuhkan aplikasi.
Semua state Svelte adalah variabel JavaScript di blok <script>. Di Svelte 5 dengan runes, gunakan $state untuk variabel yang reaktif:
<script>
let pesan = $state("Halo Svelte")
let jumlah = $state(3)
</script>
<h1>{pesan}</h1>
<p>Jumlah: {jumlah}</p>let pesan = $state("Halo Svelte") mendeklarasikan state reaktif. Kurung kurawal {pesan} di markup adalah interpolation: nilainya dirender ke teks dan diperbarui otomatis saat state berubah. Di Svelte 4, kalian cukup menulis let pesan = "Halo Svelte" tanpa $state — keduanya valid, tapi runes adalah masa depan.
Untuk menghubungkan elemen form ke state dua arah, Svelte menyediakan bind:. Nilai state berubah saat pengguna mengetik, dan tampilan ikut berubah saat state diubah dari kode:
<script>
let nama = $state("")
</script>
<input bind:value={nama} placeholder="Ketik nama" />
<p>Halo, {nama || "anonim"}!</p>bind:value={nama} membuat nama selalu sinkron dengan isi input. Ini dua arah: mengetik memperbarui state, mengubah state memperbarui input. Binding lain yang umum: bind:checked untuk checkbox, bind:files untuk input file, dan bind:this untuk referensi elemen DOM.
Di Svelte 5, event handler ditulis sebagai property elemen. Pasang fungsi atau ekspresi langsung:
<script>
let count = $state(0)
function tambah() {
count += 1
}
</script>
<button onclick={tambah}>Klik {count}</button>
<button onclick={() => (count = 0)}>Reset</button>onclick={tambah} mengikat event klik ke fungsi tambah. Di Svelte 4 sintaksnya on:click={tambah} — masih didukung, tapi bentuk property adalah gaya baru. Event lain seperti oninput, onsubmit, dan onkeydown mengikuti pola yang sama.
Untuk mem-toggle class secara reaktif, gunakan object atau array di dalam class::
<script>
let aktif = $state(false)
</script>
<button
class="tombol"
class:aktif
class:mati={!aktif}
onclick={() => (aktif = !aktif)}
>
Status: {aktif ? "aktif" : "mati"}
</button>class:aktif menambahkan class aktif saat nilai variabelnya truthy, dan menghapusnya saat falsy. Bentuk class:mati={!aktif} memakai ekspresi. Ini cara paling ergonomis untuk menata elemen berdasarkan state.
Sebelum runes, $: adalah jantung reaktivitas Svelte. Sintaks ini masih berfungsi dan berguna untuk nilai turunan:
<script>
let harga = $state(1000)
let pajak = $derived(harga * 0.11)
</script>
<p>Harga: {harga}</p>
<p>Pajak: {pajak}</p>
<p>Total: {harga + pajak}</p>let pajak = $derived(harga * 0.11) menghitung ulang pajak setiap kali harga berubah. Ini setara dengan $: pajak = harga * 0.11 di Svelte 4. Bedanya: $derived hanya untuk nilai turunan murni, sementara $: bisa memuat statement dan efek samping.
Untuk state yang dipakai banyak komponen, gunakan store dari svelte/store:
import { writable } from "svelte/store"
export const keranjang = writable([])writable([]) membuat store berisi array kosong. Komponen membaca nilainya dengan prefix $ — misalnya $keranjang — dan mengubahnya dengan method .set() atau .update(). Konsep lengkap store akan dibahas khusus di episode 6.
Untuk menampilkan blok markup berdasarkan kondisi, gunakan #if untuk blok pertama dan blok else untuk cabang kedua:
<script>
let login = $state(false)
</script>
{#if login}
<p>Selamat datang kembali!</p>
{:else}
<button onclick={() => (login = true)}>Login</button>
{/if}{#if login} membuka blok kondisional dan {/if} menutupnya. Svelte menghapus blok yang tidak terpakai dari DOM — bukan sekadar menyembunyikannya. Ini membuat conditional rendering efisien dan mudah dibaca.
Untuk merender array, gunakan #each dengan key opsional agar update list akurat:
<script>
let tugas = $state(["Belajar", "Latihan", "Deploy"])
</script>
<ul>
{#each tugas as t, i (t)}
<li>{i + 1}. {t}</li>
{/each}
</ul>{#each tugas as t, i (t)} mengiterasi array tugas, menyediakan nilai t dan indeks i. Ekspresi (t) adalah key yang membantu Svelte melacak item saat array berubah. Tanpa key, reordering list bisa menghasilkan DOM yang salah.
Inti yang harus dibawa pulang:
$state untuk variabel reaktif dan {ekspresi} untuk interpolasi di markup.bind: membuat property form dua arah; onclick mengikat event di Svelte 5.class:aktif menambah atau menghapus class berdasarkan kondisi.$derived dan $effect menggantikan mayoritas statement $: di Svelte 5.#if dan #each menangani rendering kondisional dan list.#each agar update list konsisten.Di episode 5 selanjutnya kita akan membahas component communication — bagaimana komponen saling bertukar data lewat props, slot, dan event dispatch, termasuk two-way binding dengan bind: dan pola komposisi komponen yang reusable. Sintaks template dari episode ini akan menjadi bekal utama kalian.