Formulir kontak di situs statis

Formulir kontak di situs statis5 menit baca

Menambahkan formulir kontak di Netlify tanpa Netlify Forms

Jalankan formulir kontak di situs Netlify tanpa Netlify Forms: tanpa deteksi saat build, kiriman JSON dari React, dan formulir terpisah untuk deploy preview.

Preet SutharPendiri, Ikiform

Jangan pasang data-netlify di formulir dan arahkan action-nya ke endpoint Ikiform Anda; Netlify lalu menyajikan halaman tanpa menyentuh kirimannya. Formulir React dan Vue tidak butuh salinan HTML tersembunyi, dan bisa mengirim JSON. Atur ID formulir berbeda untuk deploy preview di netlify.toml, karena host preview tidak cocok dengan situs Anda di Allowed domains.

Apa yang berbeda di Netlify

Netlify adalah satu-satunya host statis besar yang punya fitur formulir bawaan. Netlify Forms membaca HTML yang di-deploy setelah setiap build, mencari formulir bertanda data-netlify atau netlify, dan menerima kiriman ke situs Anda sendiri untuk formulir tersebut. Setiap kiriman lain ke halaman statis gagal, dan di Netlify gagalnya dengan 404, bukan 405:

Terminal
curl -i -X POST -d "message=hello" https://your-site.netlify.app/contact/
Respons
HTTP/2 404
server: Netlify
cache-status: "Netlify Edge"; fwd=method; fwd-status=404
content-length: 0

404 itu membuat orang mencari halaman yang hilang padahal tidak hilang. Artinya tidak ada formulir terdeteksi yang cocok dengan kiriman. Perlu tidaknya memakai Netlify Forms adalah pertanyaan terpisah, dan perbandingan Ikiform vs Netlify Forms menjawabnya apa adanya: jika situs Anda akan selalu di Netlify dan formulirnya HTML biasa, Netlify Forms lebih sedikit kerjanya. Halaman ini untuk kasus lainnya.

Situasi AndaMengapa Netlify Forms jadi penghalang
Formulir dirender oleh React, Vue, atau SvelteBuild mem-parsing HTML statis, jadi formulir yang dirender di klien butuh duplikat tersembunyi agar ditemukan Netlify
Anda ingin mengirim JSON dari fetchNetlify Forms hanya menerima body urlencoded dan multipart
Situs mungkin pindah ke host lainFormulir mengirim ke domain Anda sendiri, jadi hanya berfungsi selama Netlify yang menyajikan domain itu
Pesan harus sampai ke webhook yang Anda verifikasiIkiform menandatangani setiap pengiriman dengan header Standard Webhooks dan mencobanya ulang
Netlify Forms dan Ikiform berdampingan di situs Netlify yang samadengan Netlify Formsdengan IkiformbuildNetlify memindai HTMLdata-netlify?POST ke situsAndaNetlify menyimpan404 pada POSTformulir diabaikanbuildtanpa pemindaianPOST keikiform.comHTML atau JSONIkiformsimpan, email, webhookditemukantidak ditemukanNetlify Forms dan Ikiform berdampingan di situs Netlify yang samadengan Netlify Formsdengan IkiformbuildNetlify memindaiHTMLdata-netlify?POST ke situsAndaNetlify menyimpan404 padaPOSTformulirdiabaikanbuildtanpa pemindaianPOST keikiform.comHTML atau JSONIkiformsimpan, email,webhookditemukantidak ditemukan
  1. Dengan Netlify Forms, Netlify memindai HTML setiap deploy untuk mencari formulir bertanda data-netlify.
  2. Formulir yang ditemukannya menerima kiriman ke situs Anda sendiri, dan Netlify menyimpannya.
  3. Formulir yang tidak ditemukan, seperti yang dirender JavaScript tanpa salinan tersembunyi, mendapat 404 di setiap kiriman.
  4. Dengan Ikiform, tidak ada yang perlu ditemukan saat build.
  5. Formulir mengirim langsung ke ikiform.com, sebagai HTML atau JSON, lalu Ikiform menyimpannya dan mengirimi Anda email.
Keduanya bisa ada di satu situs. Formulir dengan data-netlify masuk ke Netlify; formulir yang action-nya endpoint Ikiform masuk ke Ikiform.

Memindahkan formulir dari Netlify Forms

  • Hapus data-netlify atau netlify, netlify-honeypot, dan data-netlify-recaptcha dari formulir, serta input tersembunyi form-name. Jika dibiarkan, form-name disimpan sebagai field biasa.
  • Hapus salinan statis tersembunyi dari formulir JavaScript, seperti di bawah. Netlify hanya membutuhkannya untuk mendeteksi formulir.
  • Atur action, atau URL fetch, ke endpoint Ikiform Anda. action="/thanks" yang lama dipindahkan ke pengaturan Redirect after submit formulir.
  • Unduh kiriman lama dari halaman Forms di Netlify terlebih dahulu. Kiriman itu tidak pindah dengan sendirinya.
index.html, hapus ini
<form name="contact" netlify hidden>
  <input name="name" />
  <input name="email" />
  <textarea name="message"></textarea>
</form>

Biarkan form detection aktif jika formulir lain di situs masih memakai Netlify Forms. Dokumentasi Netlify menyebutkan mematikan deteksi hanya ditujukan untuk situs yang tidak memakai Netlify Forms. Setelah tidak ada yang memakainya, mematikannya menghemat satu pemindaian di setiap deploy.

Pengganti pengaturan spam Netlify

Netlify menjalankan Akismet pada kiriman dan menyediakan netlify-honeypot serta reCAPTCHA. Di Ikiform, honeypot tetap berfungsi jika Anda mengatur Honeypot field formulir ke nama yang sudah Anda pakai, seperti bot-field. Skor spam berjalan di setiap kiriman tanpa setup, dan Spam check yang diatur ke Ikiform menggantikan reCAPTCHA dengan Cloudflare Turnstile tanpa key. Hapus div reCAPTCHA saat Anda beralih.

Formulir React yang mengirim JSON

Tanpa Netlify Forms yang menghalangi, formulir yang dirender di klien tidak butuh duplikat, dan bisa mengirim JSON, yang menjaga tipe data tetap utuh dan memungkinkan Anda merapikan nilai terlebih dahulu. Contoh ini juga mencatat context Netlify mana yang membangun halaman:

src/ContactForm.tsx
import { type FormEvent, useState } from "react";

const ENDPOINT = `https://ikiform.com/f/${import.meta.env.VITE_IKIFORM_FORM_ID}`;

interface Message {
  name: string;
  email: string;
  message: string;
  context: string;
}

export function ContactForm() {
  const [sent, setSent] = useState(false);
  const [error, setError] = useState("");

  async function onSubmit(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();
    const data = new FormData(event.currentTarget);
    const body: Message & Record<string, string> = {
      name: String(data.get("name") ?? "").trim(),
      email: String(data.get("email") ?? "").trim(),
      message: String(data.get("message") ?? "").trim(),
      context: import.meta.env.VITE_CONTEXT ?? "local",
      _gotcha: String(data.get("_gotcha") ?? ""),
    };
    setError("");
    const response = await fetch(ENDPOINT, {
      method: "POST",
      headers: { "Content-Type": "application/json", Accept: "application/json" },
      body: JSON.stringify(body),
    }).catch(() => null);
    const result = await response?.json().catch(() => null);
    if (result?.ok) return setSent(true);
    const fields: Record<string, string[]> = result?.error?.fields ?? {};
    setError(Object.values(fields)[0]?.[0] ?? result?.error?.message ?? "Couldn't send. Try again.");
  }

  if (sent) return <p role="status">Got it. I'll answer from my own inbox, usually the same day.</p>;

  return (
    <form onSubmit={onSubmit}>
      <label htmlFor="name">Name</label>
      <input id="name" name="name" autoComplete="name" required />
      <label htmlFor="email">Email</label>
      <input id="email" name="email" type="email" autoComplete="email" required />
      <label htmlFor="message">Message</label>
      <textarea id="message" name="message" rows={6} minLength={10} required />
      <input name="_gotcha" type="text" tabIndex={-1} autoComplete="off" hidden />
      {error ? <p role="alert">{error}</p> : null}
      <button>Send</button>
    </form>
  );
}
  • Content-Type: application/json memberi tahu Ikiform untuk mem-parsing JSON; Accept: application/json meminta jawaban JSON.
  • VITE_CONTEXT adalah nama contoh. Netlify mengatur CONTEXT saat build; ekspos ke Vite di perintah build Anda, atau hapus field-nya.
  • Honeypot dikirim sebagai key JSON. Tetap sertakan di body meskipun inputnya tersembunyi, agar bot yang mengisinya tetap menandai dirinya sendiri.

Deploy preview punya formulir sendiri

Deploy preview berada di host seperti deploy-preview-12--your-site.netlify.app. Itu bukan subdomain dari your-site.netlify.app, jadi tidak cocok di Allowed domains, dan kiriman preview masuk ke spam. Beri preview dan branch deploy formulir sendiri di netlify.toml, dan atur header Content-Security-Policy di file yang sama:

netlify.toml
[build]
  command = "npm run build"
  publish = "dist"

[context.production.environment]
  VITE_IKIFORM_FORM_ID = "frm_xxxxxxxxxxxxxxxx"

[context.deploy-preview.environment]
  VITE_IKIFORM_FORM_ID = "frm_yyyyyyyyyyyyyyyy"

[context.branch-deploy.environment]
  VITE_IKIFORM_FORM_ID = "frm_yyyyyyyyyyyyyyyy"

[[headers]]
  for = "/*"
  [headers.values]
    Content-Security-Policy = "default-src 'self'; form-action 'self' https://ikiform.com; connect-src 'self' https://ikiform.com"

Biarkan Allowed domains formulir preview kosong, atau tambahkan host preview persisnya selama pengujian. Formulir production mendapat domain Anda dan your-site.netlify.app. Header di netlify.toml berlaku untuk setiap deploy context; jika Anda lebih suka file _headers, file itu harus berada di publish directory.

Jangan pernah menambahkan netlify.app begitu saja ke Allowed domains. Setiap situs Netlify akan cocok, termasuk salinan formulir Anda di situs orang lain.

Pastikan berfungsi

  1. Buka deploy preview, kirim, dan pastikan pesannya masuk ke formulir preview.
  2. Merge, lalu kirim di production. Pastikan pesannya masuk ke formulir production dan halaman Forms di Netlify tidak menampilkan yang baru.
  3. Cek inbox setiap penerima notifikasi. Masing-masing mendapat email berisi field, dan Reply terkirim ke pengirim formulir jika formulir punya field email.
  4. Kirim dengan honeypot terisi, _gotcha=bot. Kiriman tetap mendapat jawaban sukses, tetapi disimpan sebagai spam dan tidak memicu email atau webhook.
  5. Tidak ada yang masuk? Ubah filter status di dashboard ke Spam. Spam mendapat jawaban sukses yang sama dengan kiriman asli.

Hal yang sering menjebak

MasalahYang harus dilakukan
404 saat mengirimKiriman masuk ke situs Anda sendiri. Build yang ter-cache mungkin masih punya action lama, atau panggilan fetch masih mengirim ke /. Cari form-name di publish directory.
Kiriman masih muncul di NetlifyAda formulir di halaman yang masih mengirim ke situs Anda sendiri dengan data-netlify atau netlify, jadi Netlify terus mendeteksi dan menyimpannya. Hapus atributnya, atur action ke Ikiform, lalu deploy ulang.
404 not_found dari Ikiform hanya di previewContext deploy preview tidak punya VITE_IKIFORM_FORM_ID, jadi URL-nya diakhiri undefined. Tambahkan di bawah [context.deploy-preview.environment].
403 origin_not_allowed, atau setiap kiriman masuk ke spamDomain halaman tidak ada di Allowed domains formulir. Tambahkan, ditambah localhost untuk uji lokal. Subdomain dari domain yang terdaftar diizinkan.
422 files_not_supportedFormulir punya <input type="file"> dengan file yang dipilih. Upload file belum didukung; hapus input itu atau minta link sebagai gantinya.

Pertanyaan

Mentok di salah satu langkah, atau ingin panduan untuk situasi Anda? Email hello@ikiform.com.