Dalam project SvelteKit, komponen adalah unit utama untuk membangun antarmuka yang rapi dan mudah dirawat. Alih-alih menulis markup yang sama berulang kali di setiap halaman, kita bisa memecah UI menjadi komponen kecil seperti Button, Card, dan Header, lalu memakainya kembali di banyak tempat.

Tutorial ini fokus pada praktik dasar yang paling relevan untuk pemula SvelteKit. Kita tidak akan membahas teori mendalam tentang compiler Svelte atau lifecycle yang kompleks. Targetnya sederhana: membuat beberapa komponen reusable, mengirim data lewat props, menangani event sederhana, memakai slot, lalu menggunakannya di halaman SvelteKit.

Struktur project yang akan dibuat

Misalkan kita sudah punya project SvelteKit yang berjalan. Struktur file yang dipakai dalam artikel ini kira-kira seperti berikut:

src/
  lib/
    components/
      Button.svelte
      Card.svelte
      Header.svelte
  routes/
    +page.svelte

Di SvelteKit, folder src/lib umum dipakai untuk menyimpan kode yang ingin dipakai ulang, termasuk komponen. Keuntungannya, komponen bisa diimpor dengan alias $lib, misalnya:

import Button from '$lib/components/Button.svelte';

Pola ini lebih nyaman dibanding memakai path relatif panjang seperti ../../lib/components/Button.svelte.

Membuat komponen Button yang reusable

Komponen tombol biasanya terlihat sederhana, tetapi justru sering dipakai di banyak tempat. Karena itu, tombol adalah kandidat bagus untuk dijadikan komponen reusable.

File Button.svelte

<script>
  export let label = 'Klik';
  export let variant = 'primary';
  export let type = 'button';
  export let disabled = false;

  const variants = {
    primary: 'background:#2563eb;color:white;',
    secondary: 'background:#e5e7eb;color:#111827;',
    danger: 'background:#dc2626;color:white;'
  };
</script>

<button
  type={type}
  disabled={disabled}
  style={`padding:0.75rem 1rem;border:none;border-radius:0.5rem;cursor:pointer;${variants[variant] || variants.primary}`}
>
  {label}
</button>

Beberapa hal penting dari komponen di atas:

  • export let ... dipakai untuk mendefinisikan props yang diterima komponen.
  • label memberi teks default jika parent tidak mengirim nilai.
  • variant dipakai untuk mengatur gaya tombol.
  • type penting terutama jika tombol dipakai di dalam form.
  • disabled diteruskan langsung ke elemen <button>.

Pendekatan ini bekerja karena komponen Svelte menerima data dari parent secara langsung lewat props. Saat nilai prop berubah, UI komponen ikut diperbarui otomatis.

Memakai Button di halaman

<script>
  import Button from '$lib/components/Button.svelte';
</script>

<Button label="Simpan" />
<Button label="Batal" variant="secondary" />
<Button label="Hapus" variant="danger" />

Dengan pola ini, kita tidak perlu menyalin markup tombol yang sama berulang kali. Jika suatu saat ingin mengubah radius, padding, atau warna dasar, cukup ubah di satu file komponen.

Menambahkan event sederhana pada Button

Karena elemen dasar di dalam komponen adalah <button>, event klik bisa langsung dipakai dari parent.

<script>
  import Button from '$lib/components/Button.svelte';

  let count = 0;

  function increment() {
    count += 1;
  }
</script>

<p>Jumlah klik: {count}</p>
<Button label="Tambah" on:click={increment} />

Ini adalah pola dasar yang sering dipakai pemula: parent mengirim props ke child, lalu parent juga menangani event dari child. Untuk kasus sederhana seperti tombol, pendekatan ini sudah cukup.

Catatan: Salah satu kesalahan umum adalah mengira semua event otomatis tersedia di semua komponen kustom. Pada komponen sederhana yang membungkus elemen HTML, pastikan event benar-benar sampai ke elemen yang diharapkan. Jika perilaku event terasa aneh, cek struktur markup komponen dan pastikan elemen interaktifnya memang yang menerima klik.

Membuat komponen Card dengan slot

Komponen Card cocok dipakai untuk membungkus konten yang berbeda-beda tetapi punya tampilan konsisten. Untuk kasus seperti ini, slot sangat berguna. Slot memungkinkan parent mengirim markup isi ke dalam komponen.

File Card.svelte

<script>
  export let title = '';
  export let bordered = true;
</script>

<div style={`padding:1rem;border-radius:0.75rem;box-shadow:0 1px 3px rgba(0,0,0,0.1);${bordered ? 'border:1px solid #e5e7eb;' : ''}`}>
  {#if title}
    <h3 style="margin-top:0;margin-bottom:0.75rem;">{title}</h3>
  {/if}

  <slot />
</div>

Di sini, komponen Card menerima dua hal:

  • Props seperti title dan bordered.
  • Isi dinamis melalui <slot />.

Kenapa slot penting? Karena tanpa slot, kita harus membuat prop terpisah untuk setiap jenis isi card. Itu cepat menjadi tidak fleksibel. Dengan slot, parent bisa mengirim paragraf, daftar, tombol, bahkan komponen lain ke dalam card.

Memakai Card di halaman

<script>
  import Card from '$lib/components/Card.svelte';
</script>

<Card title="Profil Singkat">
  <p>Halo, saya sedang belajar membangun UI dengan komponen Svelte di SvelteKit.</p>
</Card>

<Card title="Aksi" bordered={false}>
  <p>Card ini tanpa border tambahan.</p>
</Card>

Perhatikan bahwa isi di antara tag pembuka dan penutup <Card> akan masuk ke posisi <slot />. Ini menjadikan komponen card tetap sederhana tetapi fleksibel.

Menggabungkan Card dan Button

Komponen reusable akan terasa manfaatnya ketika mulai digabungkan.

<script>
  import Card from '$lib/components/Card.svelte';
  import Button from '$lib/components/Button.svelte';

  function handleBuy() {
    alert('Produk ditambahkan');
  }
</script>

<Card title="Produk">
  <p>Mouse wireless dengan baterai tahan lama.</p>
  <Button label="Beli" on:click={handleBuy} />
</Card>

Ini adalah contoh sederhana komposisi komponen: satu komponen menjadi pembungkus, komponen lain menangani interaksi.

Membuat komponen Header untuk halaman

Selanjutnya kita buat komponen Header untuk menampilkan judul dan deskripsi halaman. Komponen seperti ini berguna agar struktur halaman konsisten.

File Header.svelte

<script>
  export let title = 'Judul Halaman';
  export let subtitle = '';
</script>

<header style="margin-bottom:1.5rem;">
  <h1 style="margin:0 0 0.5rem 0;">{title}</h1>

  {#if subtitle}
    <p style="margin:0;color:#4b5563;">{subtitle}</p>
  {/if}
</header>

Komponen ini memakai conditional rendering sederhana dengan blok {#if subtitle}. Jadi paragraf subtitle hanya muncul jika prop subtitle berisi nilai.

Memakai Header di halaman utama

<script>
  import Header from '$lib/components/Header.svelte';
</script>

<Header
  title="Belajar Komponen Svelte"
  subtitle="Contoh reusable component di project SvelteKit"
/>

Untuk UI seperti header halaman, memecahnya menjadi komponen terpisah membantu menjaga file halaman tetap fokus pada susunan konten, bukan detail implementasi visual.

Menggabungkan semua komponen di +page.svelte

Sekarang kita satukan semuanya di satu halaman SvelteKit agar terlihat alur penggunaan yang lebih nyata.

File src/routes/+page.svelte

<script>
  import Header from '$lib/components/Header.svelte';
  import Card from '$lib/components/Card.svelte';
  import Button from '$lib/components/Button.svelte';

  let clickCount = 0;

  function handleClick() {
    clickCount += 1;
  }
</script>

<Header
  title="Belajar Komponen Svelte di SvelteKit"
  subtitle="Membuat Button, Card, dan Header yang reusable"
/>

<div style="display:grid;gap:1rem;">
  <Card title="Button dengan Props">
    <p>Contoh tombol dengan variasi tampilan.</p>
    <div style="display:flex;gap:0.5rem;flex-wrap:wrap;">
      <Button label="Primary" />
      <Button label="Secondary" variant="secondary" />
      <Button label="Danger" variant="danger" />
    </div>
  </Card>

  <Card title="Event Click Sederhana">
    <p>Jumlah klik saat ini: {clickCount}</p>
    <Button label="Klik saya" on:click={handleClick} />
  </Card>

  <Card title="Slot untuk Konten Bebas" bordered={true}>
    <p>Isi card ini dikirim dari halaman melalui slot.</p>
    <ul>
      <li>Bisa berisi teks</li>
      <li>Bisa berisi daftar</li>
      <li>Bisa berisi komponen lain</li>
    </ul>
  </Card>
</div>

Contoh ini menunjukkan tiga hal yang sangat penting untuk project kecil maupun menengah:

  1. Props untuk mengatur perilaku dan tampilan komponen.
  2. Event untuk interaksi dari pengguna.
  3. Slot untuk konten yang fleksibel.

Jika Anda sudah paham tiga konsep ini, Anda sudah punya fondasi yang sangat kuat untuk membangun UI di SvelteKit.

Tips struktur dan praktik yang baik untuk pemula

Simpan komponen reusable di src/lib/components

Ini memudahkan pencarian file dan import ulang. Saat jumlah komponen bertambah, Anda juga bisa membaginya ke subfolder seperti:

src/lib/components/ui/
src/lib/components/layout/
src/lib/components/forms/

Untuk tutorial dasar, satu folder components sudah cukup.

Berikan nilai default pada props bila masuk akal

Default value seperti label = 'Klik' atau variant = 'primary' membuat komponen lebih aman dipakai. Ini mengurangi bug kecil akibat prop yang lupa dikirim.

Jangan terlalu cepat membuat komponen terlalu generik

Kesalahan umum lain adalah mencoba membuat satu komponen yang bisa menangani semua kemungkinan. Akibatnya API komponen menjadi rumit, prop terlalu banyak, dan sulit dipelihara. Untuk pemula, lebih baik mulai dari komponen sederhana yang jelas tanggung jawabnya.

Gunakan slot saat struktur kontennya bisa berubah

Jika isi komponen bisa berbeda-beda antar halaman, slot biasanya lebih tepat daripada menambah prop untuk setiap potongan teks atau elemen.

Kesalahan umum dan cara debugging

Komponen tidak tampil

Periksa path import. Dalam SvelteKit, gunakan $lib/components/NamaFile.svelte bila file berada di src/lib/components.

Prop tidak terbaca

Pastikan prop dideklarasikan dengan export let. Jika Anda mengirim title dari parent tetapi child tidak punya export let title, nilainya tidak akan tersedia.

Event klik tidak bereaksi

Cek apakah event dipasang pada komponen yang memang merender elemen interaktif. Juga pastikan tombol tidak dalam keadaan disabled.

Slot tidak muncul

Pastikan komponen child memiliki <slot />. Tanpa slot, isi yang ditulis di antara tag komponen tidak akan dirender di tempat yang diharapkan.

Penutup

Komponen adalah fondasi utama saat membangun antarmuka dengan SvelteKit. Dengan memulai dari contoh sederhana seperti Button, Card, dan Header, Anda bisa belajar pola yang paling sering dipakai di project nyata: mengirim data lewat props, merespons event dari pengguna, dan menyusun konten fleksibel dengan slot.

Langkah berikutnya setelah artikel ini biasanya adalah memperbaiki styling, menambah validasi props secara disiplin, memisahkan komponen layout dan komponen UI, lalu mulai membangun halaman yang terdiri dari banyak komponen kecil. Tetapi sebagai dasar, tiga komponen di atas sudah cukup untuk memahami bagaimana SvelteKit membantu Anda menjaga kode frontend tetap modular dan mudah dirawat.