Elemen khusus Svelte adalah tag berawalan svelte: yang bukan elemen HTML. Mereka memberi komponen akses ke hal yang gak bisa ditulis sebagai markup biasa: jendela browser (<svelte:window>), bagian <head> halaman (<svelte:head>), komponen atau tag yang baru dipilih saat aplikasi jalan (<svelte:component>, <svelte:element>), dan komponen itu sendiri (<svelte:self>). Bayangin bangunan Warung Bu Sri. Dagangan di meja itu elemen HTML biasa. Tapi dari dalam, Bu Sri juga bisa melihat keluar jendela, mengganti tulisan di papan nama di atas pintu, menukar etalase di tempat yang sama, dan menata rak bertingkat yang tiap tingkatnya rak dengan bentuk yang sama. Itu bukan dagangan; itu bagian bangunan yang dia atur dari dalam.
🧪 Tebakan cepat: kode awal latihan punya
let innerWidth. Kalau kamu langsung menulis<p>Lebar: {innerWidth}px</p>tanpa<svelte:window>, paragrafnya membaca apa: lebar jendela,Lebar: 0px, atauLebar: undefinedpx? Jawabannya ada di bagian "svelte:window: jendela browser".
svelte:window: jendela browser
<script>
let lebar
let scrollY = 0
let buka = false
function tekan(event) {
if (event.key === "Escape") buka = false
}
</script>
<svelte:window bind:innerWidth={lebar} bind:scrollY on:keydown={tekan} />
<p>Lebar: {lebar}px</p>
<button class:mengambang={scrollY > 80} on:click={() => (buka = true)}>Keranjang (3)</button>
Hasilnya dari Svelte 4:
| Kejadian | Nilai di komponen | Yang tampil |
|---|---|---|
| dibuka di jendela 1.024 px | lebar = 1024 |
Lebar: 1024px |
| jendela dikecilkan jadi 375 px | lebar = 375 |
Lebar: 375px |
| halaman digulir 120 px | scrollY = 120 |
tombol Keranjang mengambang |
| tombol Escape ditekan | buka = false |
dropdown keranjang tertutup |
bind:innerWidth={lebar}mengisilebardengan lebar jendela dan memperbaruinya tiap jendela diubah ukurannya.innerHeight,outerWidth,outerHeight,devicePixelRatio, danonlinejuga bisa diikat, tapi cuma bisa dibaca.scrollXdanscrollYdua arah: mengubahscrollY = 0dari kode menggulir halaman ke atas.bind:scrollYtanpa={...}adalah singkatanbind:scrollY={scrollY}, jadi variabelnya harus bernamascrollY. Sama dengan latihan:bind:innerWidthbutuh variabel bernamainnerWidth.on:keydowndi window mendengarkan tombol di mana pun di halaman, dan Svelte melepas listener-nya sendiri saat komponennya dilepas. Bandingkan dengan actionklikDiLuardi pelajaran Actions, yang listener-nya harus kamu lepas didestroy.- Nama variabel saja gak mengikat apa pun. Tanpa
<svelte:window bind:innerWidth />,innerWidthhanyalah variabel kosong, dan paragrafnya membacaLebar: undefinedpx. Itu jawaban tebakannya.
Dua aturan, dengan pesan compiler-nya: <svelte:window> harus di tingkat teratas komponen (di dalam {#if} ditolak dengan <svelte:window> tags cannot be inside elements or blocks), dan cuma boleh satu per komponen (A component can only have one <svelte:window> tag). Untuk event di document atau <body>, ada <svelte:document> dan <svelte:body> dengan aturan yang sama.
svelte:head: judul di tab browser
<svelte:head>
<title>Keranjang ({keranjang.length}) · Warung Bu Sri</title>
</svelte:head>
Isi <svelte:head> dipindah ke <head> dokumen. Dengan dua menu di keranjang, tab browser membaca Keranjang (2) · Warung Bu Sri; tambah satu, jadi Keranjang (3) · Warung Bu Sri. Tempat yang cocok untuk <title> dan <meta name="description">. Di SvelteKit, isinya ikut dirender di server, jadi mesin pencari langsung melihat judulnya. Aturannya sama: hanya di tingkat teratas komponen.
svelte:component: pilih komponen saat jalan
<script>
import DaftarList from "./DaftarList.svelte"
import DaftarGrid from "./DaftarGrid.svelte"
export let menu
let lebar
$: tampilan = lebar < 600 ? DaftarList : DaftarGrid
</script>
<svelte:window bind:innerWidth={lebar} />
<svelte:component this={tampilan} {menu} />
- Di layar lebar, menu tampil sebagai grid kartu; di bawah 600 px, sebagai daftar.
thismenerima komponen yang diimpor, bukan string.this="DaftarList"gagal saat jalan: di mode dev denganthis={...} of <svelte:component> should specify a Svelte component., di build produksi dengancomponent is not a constructor.- Saat
tampilanberganti, komponen lama dihancurkan (onDestroy-nya jalan) dan yang baru dipasang. Props seperti{menu}dioper ke mana pun yang sedang terpasang. this={null}gak merender apa-apa, tanpa error.
svelte:element: pilih tag saat jalan
<svelte:element this={tag}>Menu</svelte:element> merender <h2>Menu</h2> saat tag = "h2", dan <p>Menu</p> saat tag = "p". Bedanya dengan svelte:component: this di sini berisi nama tag HTML sebagai string.
svelte:self: komponen di dalam dirinya sendiri
Kategori menu warung bertingkat: Menu berisi Makanan dan Minuman, Makanan berisi Nasi Goreng dan Mie Ayam. Tiap tingkat bentuknya sama, jadi satu komponen bisa memasang dirinya sendiri untuk anak-anaknya:
<!-- Kategori.svelte -->
<script>
export let simpul
</script>
<li>
{simpul.nama}
{#if simpul.anak.length > 0}
<ul>
{#each simpul.anak as anak}
<svelte:self simpul={anak} />
{/each}
</ul>
{/if}
</li>
Dengan { nama: "Menu", anak: [Makanan, Minuman] }, hasilnya daftar bertingkat: Menu, di dalamnya Makanan (Nasi Goreng, Mie Ayam) dan Minuman (Es Teh). Rekursinya berhenti di simpul yang anak-nya kosong. Karena itu <svelte:self> wajib berada di dalam {#if}, {#each}, atau slot; di tingkat teratas, compiler menolak dengan <svelte:self> components can only exist inside {#if} blocks, {#each} blocks, or slots passed to components, supaya gak terjadi rekursi tanpa akhir.
Svelte 5
<svelte:window>, <svelte:head>, <svelte:element>, <svelte:document>, dan <svelte:body> tetap sama; event-nya ditulis onkeydown. Dua yang lain sudah usang di mode runes. Komponen di Svelte 5 dinamis dengan sendirinya: let Tampilan = $derived(lebar < 600 ? DaftarList : DaftarGrid) lalu <Tampilan {menu} />, dan compiler memberi warning svelte_component_deprecated untuk <svelte:component>. Untuk rekursi, file-nya mengimpor dirinya sendiri: import Kategori from "./Kategori.svelte", dengan warning svelte_self_deprecated untuk <svelte:self>.
⚠️ Jebakan yang sering ketemu
- Variabel tanpa binding.
let innerWidthsaja gak terisi apa pun:Lebar: undefinedpx. Ikat dengan<svelte:window bind:innerWidth />. <svelte:window>atau<svelte:head>di dalam blok. Ditolak compiler. Taruh di tingkat teratas; kalau perlu bersyarat, taruh syaratnya di dalam handler atau di teks judulnya. Di Svelte 4,<title>yang dibungkus{#if}di dalam<svelte:head>cuma diisi sekali dan gak ikut berubah lagi.- String di
<svelte:component this>. Yang dioper adalah komponen yang diimpor, bukan namanya. - Yang dicek latihannya. Kodemu menyebut
svelte:windowdanbind:innerWidth, ada<p>, dan angkanya ditulis{innerWidth}, bukan diketik.
TL;DR: Tag svelte: memberi komponen akses ke bagian di luar markup biasanya. <svelte:window bind:innerWidth={lebar} bind:scrollY on:keydown={tekan} /> mengikat ukuran dan posisi gulir jendela (scrollX/scrollY dua arah, sisanya cuma dibaca) dan mendengarkan event tanpa perlu membereskan listener sendiri; tanpa binding, innerWidth cuma undefined. <svelte:head> mengisi <head>, misalnya <title>Keranjang (3) · Warung Bu Sri</title>. <svelte:component this={tampilan} /> memasang komponen yang dipilih saat jalan dan menghancurkan yang lama; this={null} gak merender apa-apa. <svelte:element this={tag}> memilih tag HTML, dan <svelte:self> memasang komponen itu sendiri untuk data bertingkat, wajib di dalam {#if} atau {#each}. svelte:window dan svelte:head cuma di tingkat teratas, satu window per komponen. Di Svelte 5, <svelte:component> dan <svelte:self> usang: komponen sudah dinamis, dan file bisa mengimpor dirinya. Latihannya: <svelte:window bind:innerWidth /> dan <p>Lebar: {innerWidth}px</p>.