Episode ini membawa gerak ke antarmuka kalian: built-in transitions, motion directives transition, in, out, dan animate, custom animation dengan tweened dan spring, serta cara memakai motion sebagai bagian dari strategi UI dan UX yang matang.

Sejauh ini kalian membangun antarmuka yang reaktif dan komunikatif. Episode 7 menambahkan dimensi yang membuat aplikasi terasa hidup: gerak. Elemen yang muncul, menghilang, dan berpindah dengan mulus tidak hanya cantik — ia memberi konteks kepada pengguna tentang apa yang sedang terjadi.
Svelte menyediakan sistem motion bawaan yang unik: kalian mendeklarasikan transition:, in:, out:, dan animate: langsung di markup, dan compiler mengurus sisanya. Tidak perlu library animasi tambahan untuk kebutuhan umum, dan tweened plus spring memberikan kendali halus untuk animasi berbasis nilai.
Di episode ini kalian akan belajar built-in transitions, motion directives, custom animation dengan tweened dan spring, serta prinsip memakai gerak secara bertanggung jawab dalam desain UX.
Svelte menyertakan fungsi transition yang siap pakai: fade, fly, slide, scale, blur, dan draw. Import dari svelte/transition dan pasang pada elemen:
<script>
import { fade, slide } from "svelte/transition"
let tampil = $state(true)
</script>
{#if tampil}
<p transition:slide>Elemen ini meluncur masuk dan keluar</p>
<p transition:fade={{ duration: 500 }}>Elemen dengan durasi khusus</p>
{/if}
<button onclick={() => (tampil = !tampil)}>Toggle</button>transition:slide membuat elemen masuk dan keluar dengan gerakan slide. Parameter object seperti { duration: 500 } dikirim lewat atribut — di sini transition:fade={{ duration: 500 }}. Gerakan keluar otomatis menggunakan transition yang sama, tidak perlu ditulis dua kali.
Terkadang kalian ingin gerakan masuk dan keluar yang berbeda. Gunakan in: dan out: secara terpisah:
<script>
import { fly, scale } from "svelte/transition"
let tampil = $state(false)
</script>
{#if tampil}
<div in:fly={{ y: 20, duration: 300 }} out:scale>
Panel muncul melayang, hilang menyusut
</div>
{/if}
<button onclick={() => (tampil = !tampil)}>Buka panel</button>in:fly={{ y: 20, duration: 300 }} menggerakkan elemen dari 20 piksel di bawah saat muncul, sedangkan out:scale menyusutkannya saat hilang. Memisahkan in: dan out: memberi kontrol penuh atas dramaturgi masuk dan keluarnya elemen.
Saat item dalam #each berpindah posisi, Svelte bisa menganimasikan perpindahannya dengan animate: — syaratnya list memakai key:
<script>
import { flip } from "svelte/animate"
let daftar = $state([1, 2, 3, 4])
function acak() {
daftar = daftar.toSorted(() => Math.random() - 0.5)
}
</script>
{#each daftar as n (n)}
<div animate:flip>{n}</div>
{/each}
<button onclick={acak}>Acak urutan</button>animate:flip menerapkan FLIP animation: item yang berpindah posisi dianimasikan secara mulus dari posisi lama ke baru. Key (n) di #each wajib agar Svelte bisa melacak identitas setiap item. Hasilnya terasa ajaib: list yang mengatur ulang dirinya dengan gerakan halus.
Perpindahan item tanpa animasi terasa tersentak — pengguna sulit mengikuti ke mana item berpindah. animate: menyelesaikan ini dengan satu atribut, tanpa library eksternal. Ini contoh sempurna filosofi Svelte: pekerjaan kompleks, sintaks minimal.
tweened dan spring adalah store dari svelte/motion yang nilai perubahannya berjalan mulus. tweened bergerak dengan durasi dan easing yang bisa diatur:
<script>
import { tweened } from "svelte/motion"
import { cubicOut } from "svelte/easing"
const nilai = tweened(0, { duration: 800, easing: cubicOut })
</script>
<button onclick={() => nilai.set(100)}>Naik ke 100</button>
<p>{$nilai}</p>tweened(0, { duration: 800, easing: cubicOut }) membuat store yang nilainya beranimasi dari nilai lama ke nilai baru selama 800 milidetik. Di belakang layar ini adalah readable store — itulah mengapa dipakai dengan $nilai di template. Cocok untuk progress bar, angka statistik, dan nilai yang bergerak linier.
spring meniru gerak fisika dengan parameter stiffness dan damping — bukan durasi tetap, melainkan kecepatan yang berubah sesuai jarak. Ini menghasilkan gerak yang terasa alami:
<script>
import { spring } from "svelte/motion"
const posisi = spring({ x: 50, y: 50 }, { stiffness: 0.1, damping: 0.25 })
</script>
<div
style="transform: translate({$posisi.x}px, {$posisi.y}px)"
onmousemove={(e) => posisi.set({ x: e.clientX, y: e.clientY })}
>
Lingkaran mengikuti kursor
</div>spring({ x: 50, y: 50 }, ...) menyimpan posisi sebagai object. Saat nilai baru di-set, spring mempercepat atau memperlambat menuju target dengan efek elastis. Nilai stiffness dan damping menentukan seberapa kencang dan berapa banyak guncangan — mainkan kedua parameter untuk nuansa yang diinginkan.
Gerak yang baik memandu perhatian, bukan mencuri perhatian. Beberapa pedoman praktis:
Aksesibilitas tidak bisa ditawar. Deteksi preferensi pengguna dengan media query CSS dan nonaktifkan animasi besar:
<script>
import { prefersReducedMotion } from "svelte/motion"
</script>
<p>Pengguna menonaktifkan animasi: {$prefersReducedMotion}</p>prefersReducedMotion adalah store bawaan Svelte 5 yang membaca media query prefers-reduced-motion dari sistem operasi pengguna. Gunakan nilainya untuk memilih antara transition penuh dan gerak minimal — penghargaan kecil yang berdampak besar bagi pengguna dengan vestibular disorder.
Inti yang harus dibawa pulang:
fade, fly, dan slide siap pakai tanpa library eksternal.in: dan out: memisahkan gerak masuk dan keluar; transition: memakai satu gerak untuk keduanya.animate:flip menganimasikan item list yang berpindah, dengan syarat key pada #each.tweened cocok untuk nilai linier dengan durasi dan easing; spring untuk gerak fisika yang alami.prefers-reduced-motion dengan store prefersReducedMotion.Di episode 8 selanjutnya kita akan membahas data fetching dan async — mengambil data dengan fetch dan async/await, reactive data loading dan error handling, load functions SvelteKit di sisi server, serta caching sederhana dan request state. Animasi dari episode ini akan mempercantik hasil fetch kalian nanti.