Pengiriman formulir HTML

Pengiriman formulir HTML6 menit baca

Validasi formulir HTML di browser dan di server

Validasi formulir dengan required, type, pattern, dan min, beri gaya error dengan :user-invalid, dan terapkan aturan yang sama di server dengan definisi field.

Preet SutharPendiri, Ikiform

Gunakan batasan bawaan HTML, seperti required, type="email", min, max, dan pattern, agar browser memblokir input yang salah sebelum apa pun dikirim. Lalu terapkan aturan yang sama di server, karena bot dan script sepenuhnya melewati browser. Dengan Ikiform, definisikan field formulir dan setiap post diperiksa: yang salah mendapat 422 validation_failed dengan pesan per field, yang bisa Anda tampilkan dengan setCustomValidity.

Contohnya adalah formulir pemesanan workshop. Formulir ini punya jenis field yang membuat validasi benar-benar berguna: jumlah tim dengan batas, tanggal yang tidak boleh di masa lalu, nomor telepon dalam satu format, dan kode booking dengan bentuk tetap.

Apa yang berbeda di sini

Ada dua validator, dan keduanya tidak melihat request yang sama. Browser hanya memeriksa orang yang memakai halaman Anda, dengan atau tanpa script. Server memeriksa semuanya, termasuk bot yang mengirim langsung ke endpoint dan kode Anda sendiri yang memanggil form.submit(), yang melewati pemeriksaan browser. Pekerjaannya adalah membuat keduanya mengatakan hal yang sama.

Post yang melewati validasi browser lalu validasi field Ikiformseseorang di halaman Andabot atau scriptkirimbatasanbrowserrequired, type,min, danpatternfieldIkiformaturan yangsama,ditegakkandisimpannilai bertipegelembungdi fieldtidak ada yangdikirimPOSTlangsungtanpa halaman,tanpapemeriksaanfieldIkiform422validation_failedtidak ada yangdisimpantidak validPost yang melewati validasi browser lalu validasi field Ikiformseseorang di halaman Andabot atau scriptkirimbatasan browserrequired, type, min,dan patternfield Ikiformaturan yang sama,ditegakkandisimpannilai bertipegelembungdi fieldtidak adayangdikirimPOST langsungtanpa halaman, tanpapemeriksaanfield Ikiform422validation_failedtidak ada yangdisimpantidak valid
  1. Seseorang mengirim formulir, dan browser memeriksa batasan di HTML. Field yang tidak valid mendapat pesan dan tidak ada yang dikirim.
  2. Post yang valid sampai ke Ikiform, yang memeriksanya terhadap definisi field formulir dan menyimpan nilai bertipe.
  3. Bot atau script mengirim langsung ke endpoint, jadi tidak ada pemeriksaan browser yang berjalan.
  4. Ikiform memeriksanya terhadap definisi yang sama dan menolaknya dengan 422 sebelum apa pun disimpan.
Lapisan browser untuk manusia. Lapisan server yang benar-benar menahan.

Lapisan browser

Pratinjau

Menjalankan validator Ikiform di browser Anda. Tidak ada yang dikirim.

Definisi yang ditegakkan Ikiform. Coba jumlah tim 25, tanggal sebelum 2 November, atau kode seperti ws-12.
workshop.html
<form id="workshop" action="https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx" method="post">
  <label for="name">Your name</label>
  <input id="name" name="name" autocomplete="name" maxlength="120" required />

  <label for="email">Work email</label>
  <input id="email" name="email" type="email" autocomplete="email" required />

  <label for="team_size">People attending</label>
  <input id="team_size" name="team_size" type="number" min="2" max="20" step="1" required />

  <label for="date">Preferred date</label>
  <input id="date" name="date" type="date" min="2026-11-02" required />

  <label for="phone">Phone</label>
  <input id="phone" name="phone" type="tel" autocomplete="tel" placeholder="+14155550123"
    pattern="\+[1-9][0-9]{6,14}" title="International format, like +14155550123" />

  <label for="code">Booking code</label>
  <input id="code" name="code" pattern="WS-[0-9]{4}" title="Codes look like WS-1234" />

  <input name="_gotcha" type="text" tabindex="-1" autocomplete="off" hidden />
  <button>Request the workshop</button>
</form>

Setiap atribut dipetakan ke satu validity state, yang bisa Anda baca dari input.validity di console:

AtributValidity stateCatatan
requiredvalueMissingUntuk grup radio, satu radio dengan required mencakup seluruh grup
type="email", type="url"typeMismatchLonggar: a@b lolos sebagai email di browser
patternpatternMismatchHarus cocok dengan seluruh nilai. Diabaikan pada field opsional yang kosong
minlength, maxlengthtooShort, tooLongHanya diperiksa setelah orang mengedit nilainya
min, maxrangeUnderflow, rangeOverflowAngka, tanggal, dan waktu
stepstepMismatchstep="1" menolak desimal
Input yang tidak bisa di-parsebadInputHuruf yang diketik ke field angka di beberapa browser
setCustomValidity()customErrorPesan apa pun yang Anda atur, sampai Anda mengosongkannya lagi

Pattern di dua engine

Browser mengompilasi pattern dengan flag v, yang lebih ketat daripada regular expression yang biasa ditulis orang: - literal di dalam character class harus di-escape, seperti [a-z\-]. Ikiform mengompilasi pattern field dengan flag u dan juga mencocokkan seluruh nilai. Tulis pattern yang valid di keduanya, seperti kode booking di atas, dan uji masing-masing di preview formulir sebelum Anda memublikasikannya.

Memberi gaya pada error

:invalid cocok dengan field wajib yang kosong begitu halaman dimuat, jadi setiap field tampil merah sebelum ada yang mengetik. :user-invalid hanya cocok setelah orang berinteraksi dengan field atau mencoba mengirim, yang hampir selalu Anda inginkan:

workshop.html
<style>
  #workshop :user-invalid {
    border-color: #b42318;
  }
</style>

Lapisan server

Tempel definisi di atas di tab Fields formulir. Sejak itu, Ikiform memvalidasi setiap post terhadapnya, dari sumber mana pun, dan menyimpan nilai yang sudah dikonversi: team_size sebagai angka, phone tanpa pemisah, date sebagai YYYY-MM-DD. Post yang melanggar aturan ditolak, tidak ada yang disimpan, dan jawabannya menyebut field mana yang gagal:

FieldDikirimPesan
team_size25Must be at most 20
team_size2.5Enter a whole number
date2026-10-30Must be on or after 2026-11-02
phone415 555 0123Use international format, e.g. +14155550123
codews-12Codes look like WS-1234
websiteNilai apa punUnknown field "website"

Baris terakhir itu penting. Dengan field terdefinisi, Ikiform menolak field apa pun yang tidak ada di definisi, jadi input yang namanya diubah gagal secara jelas alih-alih disimpan dengan nama yang salah. Field yang diawali _ dan honeypot tidak dihitung. Setiap tipe dan aturan ada di Field dan validasi.

Dengan post biasa

Tidak perlu kode. Post biasa yang ditolak menampilkan halaman error hosted Ikiform dengan status 422, setiap masalah di bawah label field Anda, dan tautan ke halaman asal post. Tombol Back browser biasanya mempertahankan isian orang itu; tautannya memuat ulang formulir dalam keadaan kosong.

Menampilkan error server di field

Dengan script, masukkan setiap pesan server ke UI error bawaan browser. setCustomValidity menandai field tidak valid dengan teks itu, dan reportValidity menampilkannya sebagai gelembung biasa dan memfokuskan yang pertama:

workshop.js
const form = document.querySelector("#workshop");

for (const control of form.elements) {
  control.addEventListener("input", () => control.setCustomValidity?.(""));
}

form.addEventListener("submit", async (event) => {
  event.preventDefault();
  const response = await fetch(form.action, {
    method: "POST",
    headers: { Accept: "application/json" },
    body: new FormData(form),
  });
  const result = await response.json();
  if (result.ok) {
    form.replaceWith("Thanks. We'll confirm the date by email.");
    return;
  }
  const fields = result.error.fields ?? {};
  for (const [name, messages] of Object.entries(fields)) {
    form.elements.namedItem(name)?.setCustomValidity?.(messages[0]);
  }
  if (!form.reportValidity()) return;
  alert(result.error.message);
});
  • Hapus pesan kustom saat input. Field dengan error kustom tetap tidak valid sampai Anda mengaturnya kembali ke string kosong, dan sampai saat itu orang sama sekali tidak bisa mengirim.
  • Pemeriksaan browser tetap berjalan sebelum event submit, jadi server hanya melihat post yang sudah lolos.
  • Jika error tidak punya fields, seperti 429 rate_limited, reportValidity() mengembalikan true dan script kembali ke pesan umum.

Memeriksa aturan server sebelum mengirim

Untuk menangkap aturan khusus server, seperti daftar domain email, sebelum request, muat definisi publik formulir dan jalankan validate dari SDK, yang menerapkan aturan dan pesan field yang sama di browser:

workshop.js
import { getSchema, validate } from "@ikiform/sdk";

const form = document.querySelector("#workshop");
const result = await getSchema("frm_xxxxxxxxxxxxxxxx");
const fields = result.ok ? result.schema.fields : [];

form.addEventListener("submit", (event) => {
  const errors = validate(fields, new FormData(form));
  for (const control of form.elements) control.setCustomValidity?.(errors[control.name] ?? "");
  if (!form.reportValidity()) event.preventDefault();
});
Anggap ini sebagai kemudahan. Server tetap menjadi sumber kebenaran, dan getSchema hanya mengekspos definisi field, yang memang publik: siapa pun bisa membacanya dari /f/<formId>/schema.

Pastikan berfungsi

  1. Di Allowed domains formulir, tambahkan domain situs Anda, ditambah localhost selama pengembangan. Biarkan kosong untuk menerima kiriman dari mana saja.
  2. Kirim formulir kosong. Browser menghentikannya di Your name dan tidak ada yang muncul di panel Network.
  3. Hapus max dari jumlah tim di developer tools, masukkan 25, lalu kirim. Post biasa menampilkan halaman error Ikiform; versi script menampilkan Must be at most 20 di field.
  4. Kirim dengan curl, melewati browser: curl -H "Accept: application/json" -H "Origin: https://example.com" -d team_size=abc https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx, dengan allowed domain Anda sendiri sebagai origin. Jawabannya 422 dengan pesan untuk team_size dan setiap field wajib yang hilang.
  5. Buka Submissions di dashboard. Kiriman baru ada di sana dengan setiap field yang Anda kirim.

Hal yang sering menjebak

MasalahPenyebab dan solusi
Formulir tidak pernah terkirim setelah error serverPesan custom validity tidak pernah dihapus. Reset dengan setCustomValidity("") saat input
minlength tidak terpicu pada nilai yang sudah terisitooShort hanya berlaku setelah orang mengedit field. Aturan server yang menangkapnya
pattern diabaikan sepenuhnyaPattern itu tidak valid di bawah flag v, dan browser melewati pattern yang tidak valid sepenuhnya. Escape - dan karakter khusus lain di dalam class
Error tampil sebelum ada yang mengetikCSS memakai :invalid. Ganti ke :user-invalid
422 validation_failedKiriman tidak cocok dengan definisi field formulir. error.fields menyebutkan setiap field dan alasannya. Samakan name input dengan ID field.

Alur pengiriman lengkap ada di ringkasan, dan Errors mencantumkan setiap kode yang bisa didapat sebuah post.

Pertanyaan

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