Belajar SvelteKit - Forms, Validation, & Interaction
Episode 11 of 24

Belajar SvelteKit - Forms, Validation, & Interaction

Episode ini membahas form secara mendalam: alur submit dan validasi, validasi di sisi server dengan umpan balik UI, progressive enhancement dengan no-JS fallback, serta file upload dengan multipart form. Kalian akan membangun form yang aman dan tetap berfungsi tanpa JavaScript.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Pendahuluan

Form adalah titik pertemuan antara pengguna dan data: pendaftaran, login, komentar, hingga unggah gambar. Episode 11 membahas form secara menyeluruh — dari alur submit yang benar, validasi di server, hingga pengalaman tanpa JavaScript.

Prinsip utama yang dipegang SvelteKit adalah progressive enhancement: form yang ditulis dengan HTML standar berfungsi meski JavaScript mati. Lapisan JS kemudian menambahkan pengalaman yang lebih halus — validasi instan, tidak kehilangan state, dan feedback yang responsif.

Setelah episode ini, kalian bisa membangun form yang aman, memberikan umpan balik yang jelas kepada pengguna, dan menangani file upload tanpa tersandera oleh teknologi tertentu.

Alur Submit dan Prinsip Dasar

Form HTML Standar

Semua bermula dari form HTML biasa: elemen form dengan atribut method dan action. Tanpa JavaScript, browser mengirim data sebagai POST dan memuat ulang halaman — ini adalah baseline yang harus selalu berfungsi.

Form dasar
<form method="POST" action="?/daftar">
    <label for="email">Email</label>
    <input id="email" name="email" type="email" required />
 
    <label for="password">Password</label>
    <input id="password" name="password" type="password" required minlength="8" />
 
    <button type="submit">Daftar</button>
</form>

Atribut action="?/daftar" menargetkan server action bernama daftar di +page.server.js yang sejalan. Elemen input wajib memiliki atribut name, karena nama itulah kunci data di server.

Membaca FormData di Server

Server action menerima request dan membaca data lewat request.formData(). Setiap nilai dibaca sebagai string; angka harus dikonversi manual.

Validasi di Sisi Server

Mengembalikan Nilai Bersama Error

Validasi utama harus selalu di server — validasi client hanya kenyamanan, bukan keamanan. Gunakan helper fail dari @sveltejs/kit untuk mengembalikan nilai form beserta pesan error dengan status 4xx.

JSValidasi dan fail
import { fail } from "@sveltejs/kit";
 
export const actions = {
    daftar: async ({ request }) => {
        const form = await request.formData();
        const nama = String(form.get("nama") ?? "");
        const email = String(form.get("email") ?? "");
 
        if (nama.length < 3) {
            return fail(400, { nama, email, error: "Nama minimal 3 karakter" });
        }
 
        if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
            return fail(400, { nama, email, error: "Format email tidak valid" });
        }
 
        await simpanPengguna({ nama, email });
 
        return { sukses: true };
    }
};

Nilai yang dikembalikan dari action menjadi prop form di komponen. Dengan mengembalikan kembali input yang salah, kalian bisa mengisi ulang field tanpa meminta pengguna mengetik ulang.

Umpan Balik di UI

Feedback dari hasil action
<script>
    import { enhance } from "$app/forms";
 
    let { form } = $props();
</script>
 
<form method="POST" action="?/daftar" use:enhance>
    <label for="nama">Nama</label>
    <input id="nama" name="nama" value={form?.nama ?? ""} />
 
    {#if form?.error}
        <p class="error" role="alert">{form.error}</p>
    {/if}
 
    <button type="submit">Daftar</button>
</form>

Prop form tersedia setelah action pertama kali dijalankan. Perhatikan penggunaan role="alert" untuk accessibility: pembaca layar mengumumkan error tanpa memindahkan fokus secara paksa.

Progressive Enhancement dan No-JS Fallback

use:enhance sebagai Lapisan

Directive use:enhance mengubah submit native menjadi fetch. Hasilnya: halaman tidak reload, form tidak kehilangan fokus, dan pengembang bisa menambahkan transisi atau update parsial.

use:enhance dengan feedback loading
<script>
    import { enhance } from "$app/forms";
 
    let { form } = $props();
    let mengirim = $state(false);
</script>
 
<form method="POST" action="?/daftar"
    use:enhance={() => {
        mengirim = true;
        return async ({ update }) => {
            await update();
            mengirim = false;
        };
    }}>
    <button type="submit" disabled={mengirim}>
        {mengirim ? "Mengirim..." : "Daftar"}
    </button>
</form>

Fungsi yang dikembalikan dari callback use:enhance menerima object berisi update, result, dan form. Panggil update() untuk menerapkan hasil action ke halaman. Jika JavaScript gagal dimuat, form tetap berjalan sebagai POST native — tidak ada data yang hilang.

Pengujian Tanpa JS

Selalu uji form dalam kondisi no-JS, misalnya dengan mematikan JavaScript di devtools atau lewat test E2E seperti npx playwright test. Ini menjamin jalur paling dasar tetap bekerja dan menjadi safety net untuk pengguna dengan koneksi lambat atau browser yang membatasi skrip.

File Upload dan Multipart Form

Membaca File di Action

Upload file bekerja lewat form dengan enctype="multipart/form-data". Di server, nilai file muncul sebagai objek File di dalam FormData.

JSMenangani file upload
export const actions = {
    unggah: async ({ request }) => {
        const form = await request.formData();
        const file = form.get("gambar");
 
        if (!(file instanceof File) || file.size === 0) {
            return fail(400, { error: "Pilih file terlebih dahulu" });
        }
 
        if (file.size > 5 * 1024 * 1024) {
            return fail(400, { error: "Ukuran file maksimal 5 MB" });
        }
 
        const bytes = new Uint8Array(await file.arrayBuffer());
        await simpanKeStorage(file.name, file.type, bytes);
 
        return { sukses: true };
    }
};

Selalu batasi ukuran dan tipe file di server, bukan hanya di client. Untuk file besar, pertimbangkan menyimpan langsung ke object storage (misalnya S3 atau R2) dan simpan hanya metadata-nya di database.

Batas Payload

Serverless dan edge runtime sering punya batas ukuran request. Periksa batas provider kalian dan beri pesan yang jelas saat upload melewati limit. Untuk file yang sangat besar, strategi yang tepat adalah upload langsung ke storage lewat presigned URL, di mana server hanya menandatangani izin tanpa memindahkan byte-nya.

Penutup

Inti yang harus dibawa pulang:

  • Form HTML standar adalah baseline; server actions menangani POST dengan aman.
  • Validasi utama ada di server; fail mengembalikan nilai dan error dengan status 4xx.
  • Prop form membawa hasil action ke komponen untuk umpan balik UI.
  • use:enhance menambah lapisan JS tanpa menghilangkan fallback native.
  • Selalu uji form dalam kondisi no-JS untuk menjamin jalur dasar berfungsi.
  • File upload butuh validasi ukuran dan tipe di server, dan pertimbangkan object storage untuk file besar.

Di episode 12 selanjutnya kita masuk ke authentication & authorization: auth patterns di SvelteKit, session handling dengan cookies dan server-side auth, protected routes dan authorization guards, serta external auth providers seperti OAuth dan OIDC.

Belajar SvelteKit - Forms, Validation, & Interaction | Belajar SvelteKit