Belajar Gatsby - Forms & Interactivity
Episode 10 of 24

Belajar Gatsby - Forms & Interactivity

Episode ini membahas form dan interaktivitas di Gatsby: form dengan client-side state, pengiriman lewat Netlify Forms dan Gatsby Functions, navigasi client-side, serta pola aksesibilitas dan feedback pengguna.

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

Pendahuluan

Situs statis bukan berarti statis total. Halaman yang di-generate saat build tetap bisa menampung form kontak, pencarian produk, atau filter data yang berjalan penuh di browser. Gatsby menyediakan React di sisi client dan Gatsby Functions di sisi server sehingga kombinasi keduanya menghasilkan interaksi yang lengkap.

Episode 10 membahas form dengan client-side state, pengiriman form lewat Netlify Forms dan Gatsby Functions, navigasi client-side serta perilaku dinamis, dan terakhir pola aksesibilitas serta feedback pengguna yang baik.

Membangun Form dengan Client-Side State

Controlled Input dengan useState

Form di Gatsby pada dasarnya adalah form React. Setiap input menyimpan nilainya di state, lalu state tersebut yang dipakai untuk validasi dan pengiriman. Setelah proses hydration selesai, seluruh handler bekerja normal seperti aplikasi React biasa.

JSForm kontak controlled dengan useState
import { useState } from "react"
 
const ContactForm = () => {
  const [values, setValues] = useState({ name: "", email: "", message: "" })
 
  const handleChange = (event) => {
    const { name, value } = event.target
    setValues((prev) => ({ ...prev, [name]: value }))
  }
 
  const handleSubmit = (event) => {
    event.preventDefault()
    console.log(values)
  }
 
  return (
    <form onSubmit={handleSubmit}>
      <label htmlFor="name">Nama</label>
      <input id="name" name="name" onChange={handleChange} />
      <label htmlFor="email">Email</label>
      <input id="email" name="email" type="email" onChange={handleChange} />
      <label htmlFor="message">Pesan</label>
      <textarea id="message" name="message" onChange={handleChange} />
      <button type="submit">Kirim</button>
    </form>
  )
}
 
export default ContactForm

Pola atribut name yang sama pada setiap input membuat handler handleChange bisa dipakai ulang untuk semua field. Inilah yang disebut controlled component: nilai input berasal dari state, bukan sebaliknya.

Validasi Ringan di Client

Validasi bisa dilakukan sebelum pengiriman dengan memeriksa isi state. Namun validasi client saja tidak cukup — form tetap harus divalidasi di sisi server. handleSubmit di atas baru mencetak data ke konsol; pada bagian berikutnya kita ganti dengan pengiriman nyata.

Pengiriman Form ke Backend

Netlify Forms

Netlify Forms memungkinkan form Gatsby terkirim tanpa menulis server. Saat deploy ke Netlify, file HTML hasil build dipindai dan form yang memenuhi aturan otomatis menjadi endpoint. Tambahkan atribut name pada form dan field tersembunyi:

JSForm dengan Netlify Forms
<form
  name="contact"
  method="POST"
  data-netlify="true"
  netlify-honeypot="bot-field"
>
  <input type="hidden" name="form-name" value="contact" />
  <input type="hidden" name="bot-field" />
  <input type="text" name="name" placeholder="Nama" />
  <input type="email" name="email" placeholder="Email" />
  <textarea name="message" placeholder="Pesan" />
  <button type="submit">Kirim</button>
</form>

Saat pengguna submit, browser mengirim POST langsung ke Netlify dan submission muncul di dashboard Netlify. Netlify Forms paling cocok untuk situs yang memang di-host di Netlify dan tidak memerlukan logika server tambahan.

Gatsby Functions sebagai Serverless Handler

Jika kalian butuh logika khusus — validasi lanjutan, notifikasi email, atau integrasi CRM — Gatsby Functions menyediakan endpoint serverless di dalam project. Simpan file di folder src/api:

JSEndpoint API kontak di src/api/contact.ts
import type { GatsbyFunctionRequest, GatsbyFunctionResponse } from "gatsby"
 
const handler = (request: GatsbyFunctionRequest, response: GatsbyFunctionResponse) => {
  const { name, email, message } = request.body
 
  if (!email || !message) {
    response.status(400).json({ error: "Email dan pesan wajib diisi" })
    return
  }
 
  response.status(200).json({ ok: true, received: { name, email } })
}
 
export default handler

Setiap file di src/api otomatis menjadi endpoint /api/{nama-file} tanpa konfigurasi tambahan. Di development, Gatsby Functions berjalan bersama gatsby develop; di production, mereka didistribusikan sebagai fungsi tanpa server sesuai platform hosting.

Dari komponen form, kirim data dengan fetch:

JSSubmit form ke Gatsby Function
const handleSubmit = async (event) => {
  event.preventDefault()
  setStatus("loading")
 
  const res = await fetch("/api/contact", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(values),
  })
 
  if (res.ok) {
    setStatus("success")
  } else {
    setStatus("error")
  }
}

fetch("/api/contact", ...) mengirim JSON ke endpoint Gatsby Function. Response ok: true dari server dipakai untuk mengubah status UI menjadi sukses.

Navigasi antar halaman di Gatsby menggunakan komponen Link, bukan tag a, agar transisi dilakukan di client tanpa reload penuh. Untuk navigasi yang dipicu aksi lain, gunakan fungsi navigate:

JSNavigasi programatik dengan navigate
import { navigate } from "gatsby"
 
const handleSuccess = () => navigate("/terima-kasih")

navigate("/terima-kasih") berpindah halaman secara client-side sambil tetap memanfaatkan prefetching Gatsby. Prefetching membuat halaman tujuan sudah dimuat lebih awal, sehingga transisi terasa instan.

Client-Only Routes

Untuk halaman yang hanya eksis di client, misalnya dashboard pengguna, gunakan pola client-only route dengan @reach/router yang sudah dibundel Gatsby. Buat halaman tempat kosong lalu render komponen dinamis yang membaca path dari prop location.

Aksesibilitas dan Feedback Pengguna

Label, Focus, dan ARIA

Setiap input wajib memiliki label. Gunakan htmlFor pada label dan id pada input agar keduanya terhubung, sehingga pembaca layar dapat mengumumkan label dengan benar. Untuk pesan error, gunakan aria-describedby agar assistive technology membacakan keterkaitan antara input dan pesan errornya.

Feedback dengan aria-live

Feedback status — loading, sukses, atau error — harus diumumkan tanpa mengubah fokus pengguna secara tiba-tiba. Gunakan region aria-live="polite" yang akan dibacakan pembaca layar saat kontennya berubah:

JSFeedback aksesibel dengan aria-live
const FormStatus = ({ status }) => (
  <div aria-live="polite">
    {status === "loading" && "Mengirim data..."}
    {status === "success" && "Terima kasih, pesan kalian terkirim."}
    {status === "error" && "Terjadi kesalahan, coba lagi."}
  </div>
)

aria-live="polite" memastikan pembaca layar mengumumkan perubahan status tanpa interupsi. Selain itu, hindari menonaktifkan tombol submit tanpa alasan, dan berikan indikator visual yang jelas saat tombol sedang sibuk memproses.

Penutup

Inti yang harus dibawa pulang:

  • Form Gatsby adalah form React dengan controlled state.
  • Netlify Forms cocok untuk pengiriman sederhana tanpa server.
  • Gatsby Functions menyediakan endpoint serverless untuk logika kustom.
  • Gunakan Link dan navigate untuk navigasi client-side.
  • Label, aria-describedby, dan aria-live wajib untuk aksesibilitas.
  • Validasi client harus didampingi validasi server.

Di episode 11 selanjutnya kita akan membahas localization dan i18n — cara menginternasionalisasi situs Gatsby, multi-language routing, terjemahan konten, serta SEO untuk halaman berbahasa banyak.

Belajar Gatsby - Forms & Interactivity | Belajar Gatsby