Build a copy-paste contact form for React, Next.js, Vue, Astro, or plain HTML — wired to a free form backend, with silent spam protection and no server code to write.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Contact Us</title>
</head>
<body>
<form id="formigo-form" action="https://formigo.io/f/your-form" method="POST">
<div>
<label for="name">Name</label>
<input type="text" id="name" name="name" required>
</div>
<div>
<label for="email">Email</label>
<input type="email" id="email" name="email" required>
</div>
<div>
<label for="message">Message</label>
<textarea id="message" name="message" rows="5" required></textarea>
</div>
<!-- Spam protection: honeypot stays empty; timestamp set on load -->
<input type="text" name="_formigo_hp" value="" style="display:none" tabindex="-1" autocomplete="off">
<input type="hidden" name="_formigo_t" value="">
<button type="submit">Send message</button>
<p id="formigo-status" role="status" aria-live="polite"></p>
</form>
<script>
const form = document.getElementById("formigo-form");
const statusEl = document.getElementById("formigo-status");
form.elements._formigo_t.value = Math.floor(Date.now() / 1000);
form.addEventListener("submit", async (e) => {
e.preventDefault();
const submitBtn = form.querySelector("button[type=submit]");
const data = Object.fromEntries(new FormData(form));
submitBtn.disabled = true;
statusEl.textContent = "";
try {
const response = await fetch("https://formigo.io/f/your-form", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(data),
});
if (response.ok) {
statusEl.textContent = "Thanks! Your message is on its way.";
form.reset();
form.elements._formigo_t.value = Math.floor(Date.now() / 1000);
} else if (response.status === 429) {
const { retry_after } = await response.json();
statusEl.textContent = `Too fast! Try again in ${retry_after}s.`;
} else {
statusEl.textContent = "Something went wrong. Please try again.";
}
} catch (error) {
statusEl.textContent = "Network error. Please try again.";
} finally {
submitBtn.disabled = false;
}
});
</script>
</body>
</html>
The code above posts to formigo.io/f/your-form.
Create a free Formigo form, swap in your slug, and submissions land in your inbox, Slack, or Google Sheets.
Yes. The generator is completely free and needs no signup. The code it produces posts to Formigo, which has a free-forever plan with no credit card required.
It generates a contact form for plain HTML and JavaScript, React, Next.js (App Router Client Component), Vue 3, and Astro. Pick a framework and copy the code.
When spam protection is on, the code includes a hidden honeypot field named _formigo_hp and a timestamp field named _formigo_t set on load. Formigo scores bots from these without any CAPTCHA. You can layer on hCaptcha or Cloudflare Turnstile later.
To wherever you configure in Formigo: an email address, a Slack channel, a Discord channel, a Google Sheet, or a webhook. You can enable several at once on the same form.
No. The form posts directly to your Formigo endpoint, which stores the submission and delivers it. There is no server code to write or host.