Real-world integration examples for popular frameworks and platforms.
The simplest way to get started
A basic HTML form that works anywhere - no framework required.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Contact Form</title>
<style>
.form-group { margin-bottom: 1rem; }
label { display: block; margin-bottom: 0.5rem; }
input, textarea {
width: 100%;
padding: 0.5rem;
border: 1px solid #ccc;
border-radius: 4px;
}
button {
padding: 0.75rem 1.5rem;
background: #FF6B9D;
color: white;
border: none;
border-radius: 8px;
cursor: pointer;
}
</style>
</head>
<body>
<h1>Contact Us</h1>
<form action="https://formigo.com/f/your-form" method="POST">
<div class="form-group">
<label for="name">Name *</label>
<input type="text" id="name" name="name" required>
</div>
<div class="form-group">
<label for="email">Email *</label>
<input type="email" id="email" name="email" required>
</div>
<div class="form-group">
<label for="message">Message *</label>
<textarea id="message" name="message" rows="5" required></textarea>
</div>
<!-- Spam protection -->
<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>
</form>
<script>
document.querySelector('input[name="_formigo_t"]').value =
Math.floor(Date.now() / 1000);
</script>
</body>
</html>
Modern React approach using hooks and fetch
A complete React component with state management, error handling, and success messages.
import { useState, useEffect } from "react";
export default function ContactForm() {
const [formData, setFormData] = useState({
name: "",
email: "",
message: "",
});
const [status, setStatus] = useState("");
const [loading, setLoading] = useState(false);
// Set timestamp when component mounts
useEffect(() => {
setFormData(prev => ({
...prev,
_formigo_t: Math.floor(Date.now() / 1000)
}));
}, []);
const handleChange = (e) => {
setFormData({
...formData,
[e.target.name]: e.target.value,
});
};
const handleSubmit = async (e) => {
e.preventDefault();
setLoading(true);
setStatus("");
try {
const response = await fetch("https://formigo.com/f/your-form", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
...formData,
_formigo_hp: "", // Honeypot
}),
});
if (response.ok) {
setStatus("success");
setFormData({ name: "", email: "", message: "" });
} else if (response.status === 429) {
const data = await response.json();
setStatus(`Rate limited. Try again in ${data.retry_after}s`);
} else {
setStatus("error");
}
} catch (error) {
setStatus("error");
console.error("Error:", error);
} finally {
setLoading(false);
}
};
return (
<div className="max-w-md mx-auto">
<h2 className="text-2xl font-bold mb-4">Contact Us</h2>
<form onSubmit={handleSubmit} className="space-y-4">
<div>
<label htmlFor="name" className="block mb-2">
Name *
</label>
<input
type="text"
id="name"
name="name"
value={formData.name}
onChange={handleChange}
required
className="w-full px-4 py-2 border rounded-lg"
/>
</div>
<div>
<label htmlFor="email" className="block mb-2">
Email *
</label>
<input
type="email"
id="email"
name="email"
value={formData.email}
onChange={handleChange}
required
className="w-full px-4 py-2 border rounded-lg"
/>
</div>
<div>
<label htmlFor="message" className="block mb-2">
Message *
</label>
<textarea
id="message"
name="message"
value={formData.message}
onChange={handleChange}
required
rows={5}
className="w-full px-4 py-2 border rounded-lg"
/>
</div>
<button
type="submit"
disabled={loading}
className="w-full px-6 py-3 bg-pink-500 text-white rounded-lg
hover:bg-pink-600 disabled:opacity-50"
>
{loading ? "Sending..." : "Send Message"}
</button>
{status === "success" && (
<p className="text-green-600">
Thank you! Your message has been sent.
</p>
)}
{status === "error" && (
<p className="text-red-600">
Something went wrong. Please try again.
</p>
)}
{status && status.includes("Rate limited") && (
<p className="text-yellow-600">{status}</p>
)}
</form>
</div>
);
}
Using Composition API
<template>
<div class="max-w-md mx-auto">
<h2 class="text-2xl font-bold mb-4">Contact Us</h2>
<form @submit.prevent="handleSubmit" class="space-y-4">
<div>
<label for="name" class="block mb-2">Name *</label>
<input
type="text"
id="name"
v-model="formData.name"
required
class="w-full px-4 py-2 border rounded-lg"
/>
</div>
<div>
<label for="email" class="block mb-2">Email *</label>
<input
type="email"
id="email"
v-model="formData.email"
required
class="w-full px-4 py-2 border rounded-lg"
/>
</div>
<div>
<label for="message" class="block mb-2">Message *</label>
<textarea
id="message"
v-model="formData.message"
required
rows="5"
class="w-full px-4 py-2 border rounded-lg"
/>
</div>
<button
type="submit"
:disabled="loading"
class="w-full px-6 py-3 bg-pink-500 text-white rounded-lg
hover:bg-pink-600 disabled:opacity-50"
>
{{ loading ? "Sending..." : "Send Message" }}
</button>
<p v-if="status === 'success'" class="text-green-600">
Thank you! Your message has been sent.
</p>
<p v-if="status === 'error'" class="text-red-600">
Something went wrong. Please try again.
</p>
</form>
</div>
</template>
<script setup>
import { ref, onMounted } from "vue";
const formData = ref({
name: "",
email: "",
message: "",
_formigo_t: 0,
});
const loading = ref(false);
const status = ref("");
// Set timestamp when component mounts
onMounted(() => {
formData.value._formigo_t = Math.floor(Date.now() / 1000);
});
const handleSubmit = async () => {
loading.value = true;
status.value = "";
try {
const response = await fetch("https://formigo.com/f/your-form", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
...formData.value,
_formigo_hp: "", // Honeypot
}),
});
if (response.ok) {
status.value = "success";
formData.value = {
name: "",
email: "",
message: "",
_formigo_t: Math.floor(Date.now() / 1000),
};
} else {
status.value = "error";
}
} catch (error) {
status.value = "error";
console.error("Error:", error);
} finally {
loading.value = false;
}
};
</script>
For legacy projects
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Contact Form</title>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<style>
.form-group { margin-bottom: 1rem; }
label { display: block; margin-bottom: 0.5rem; }
input, textarea {
width: 100%;
padding: 0.5rem;
border: 1px solid #ccc;
}
.message { padding: 1rem; margin-top: 1rem; border-radius: 4px; }
.success { background: #d4edda; color: #155724; }
.error { background: #f8d7da; color: #721c24; }
</style>
</head>
<body>
<h1>Contact Us</h1>
<form id="contact-form">
<div class="form-group">
<label for="name">Name *</label>
<input type="text" id="name" name="name" required>
</div>
<div class="form-group">
<label for="email">Email *</label>
<input type="email" id="email" name="email" required>
</div>
<div class="form-group">
<label for="message">Message *</label>
<textarea id="message" name="message" rows="5" required></textarea>
</div>
<button type="submit">Send Message</button>
</form>
<div id="status-message"></div>
<script>
$(document).ready(function() {
// Set timestamp
const timestamp = Math.floor(Date.now() / 1000);
$("#contact-form").on("submit", function(e) {
e.preventDefault();
const formData = {
name: $("#name").val(),
email: $("#email").val(),
message: $("#message").val(),
_formigo_hp: "", // Honeypot
_formigo_t: timestamp
};
$.ajax({
url: "https://formigo.com/f/your-form",
method: "POST",
contentType: "application/json",
data: JSON.stringify(formData),
beforeSend: function() {
$("button[type=submit]").prop("disabled", true)
.text("Sending...");
$("#status-message").empty();
},
success: function() {
$("#status-message").html(
'<div class="message success">Thank you! Your message has been sent.</div>'
);
$("#contact-form")[0].reset();
},
error: function(xhr) {
let message = "Something went wrong. Please try again.";
if (xhr.status === 429) {
const data = xhr.responseJSON;
message = `Rate limited. Try again in ${data.retry_after} seconds.`;
}
$("#status-message").html(
`<div class="message error">${message}</div>`
);
},
complete: function() {
$("button[type=submit]").prop("disabled", false)
.text("Send Message");
}
});
});
});
</script>
</body>
</html>
No plugins required
Add a contact form to any WordPress page or post. Works with Gutenberg and Classic Editor.
Create a file contact-form.php in your theme directory:
<!-- wp:html -->
<div class="formigo-contact-form">
<form id="formigo-form" action="https://formigo.com/f/your-form" method="POST">
<div class="form-group">
<label for="name">Name *</label>
<input type="text" id="name" name="name" required>
</div>
<div class="form-group">
<label for="email">Email *</label>
<input type="email" id="email" name="email" required>
</div>
<div class="form-group">
<label for="message">Message *</label>
<textarea id="message" name="message" rows="5" required></textarea>
</div>
<!-- Spam protection -->
<input type="text" name="_formigo_hp" value=""
style="display:none" tabindex="-1" autocomplete="off">
<input type="hidden" name="_formigo_t" id="formigo-timestamp">
<button type="submit">Send Message</button>
</form>
<div id="formigo-status"></div>
</div>
<style>
.formigo-contact-form { max-width: 600px; margin: 2rem 0; }
.form-group { margin-bottom: 1.5rem; }
.form-group label { display: block; margin-bottom: 0.5rem; font-weight: 600; }
.form-group input,
.form-group textarea {
width: 100%;
padding: 0.75rem;
border: 2px solid #ddd;
border-radius: 8px;
}
button {
padding: 0.75rem 2rem;
background: #FF6B9D;
color: white;
border: none;
border-radius: 8px;
font-weight: 600;
cursor: pointer;
}
#formigo-status { margin-top: 1rem; padding: 1rem; border-radius: 8px; }
.success { background: #d4edda; color: #155724; }
.error { background: #f8d7da; color: #721c24; }
</style>
<script>
document.addEventListener("DOMContentLoaded", function() {
// Set timestamp
document.getElementById("formigo-timestamp").value =
Math.floor(Date.now() / 1000);
// Handle form submission
document.getElementById("formigo-form").addEventListener("submit", async function(e) {
e.preventDefault();
const form = e.target;
const status = document.getElementById("formigo-status");
const submitBtn = form.querySelector("button[type=submit]");
// Disable button
submitBtn.disabled = true;
submitBtn.textContent = "Sending...";
status.innerHTML = "";
try {
const formData = new FormData(form);
const data = Object.fromEntries(formData);
const response = await fetch(form.action, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(data)
});
if (response.ok) {
status.className = "success";
status.innerHTML = "Thank you! Your message has been sent.";
form.reset();
document.getElementById("formigo-timestamp").value =
Math.floor(Date.now() / 1000);
} else {
throw new Error("Submission failed");
}
} catch (error) {
status.className = "error";
status.innerHTML = "Something went wrong. Please try again.";
} finally {
submitBtn.disabled = false;
submitBtn.textContent = "Send Message";
}
});
});
</script>
<!-- /wp:html -->
your-form with your actual form slugNo dependencies, pure ES6+
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Contact Form</title>
<style>
.form-group { margin-bottom: 1rem; }
label { display: block; margin-bottom: 0.5rem; font-weight: 600; }
input, textarea {
width: 100%;
padding: 0.75rem;
border: 2px solid #ddd;
border-radius: 8px;
}
button {
padding: 0.75rem 2rem;
background: #6BCF7F;
color: white;
border: none;
border-radius: 8px;
font-weight: 600;
cursor: pointer;
}
.message { padding: 1rem; margin-top: 1rem; border-radius: 8px; }
.success { background: #d4edda; color: #155724; }
.error { background: #f8d7da; color: #721c24; }
</style>
</head>
<body>
<h1>Contact Us</h1>
<form id="contact-form">
<div class="form-group">
<label for="name">Name *</label>
<input type="text" id="name" name="name" required>
</div>
<div class="form-group">
<label for="email">Email *</label>
<input type="email" id="email" name="email" required>
</div>
<div class="form-group">
<label for="message">Message *</label>
<textarea id="message" name="message" rows="5" required></textarea>
</div>
<input type="hidden" id="timestamp" name="_formigo_t">
<button type="submit">Send Message</button>
</form>
<div id="status"></div>
<script>
// Set timestamp when page loads
document.getElementById("timestamp").value = Math.floor(Date.now() / 1000);
// Handle form submission
document.getElementById("contact-form").addEventListener("submit", async (e) => {
e.preventDefault();
const form = e.target;
const status = document.getElementById("status");
const submitBtn = form.querySelector("button[type=submit]");
// Get form data
const formData = new FormData(form);
const data = Object.fromEntries(formData);
data._formigo_hp = ""; // Add honeypot
// Disable button
submitBtn.disabled = true;
submitBtn.textContent = "Sending...";
status.innerHTML = "";
try {
const response = await fetch("https://formigo.com/f/your-form", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(data)
});
if (response.ok) {
status.className = "message success";
status.textContent = "Thank you! Your message has been sent.";
form.reset();
// Reset timestamp
document.getElementById("timestamp").value =
Math.floor(Date.now() / 1000);
} else if (response.status === 429) {
const result = await response.json();
status.className = "message error";
status.textContent = `Rate limited. Try again in ${result.retry_after} seconds.`;
} else {
throw new Error("Submission failed");
}
} catch (error) {
status.className = "message error";
status.textContent = "Something went wrong. Please try again.";
console.error("Error:", error);
} finally {
submitBtn.disabled = false;
submitBtn.textContent = "Send Message";
}
});
</script>
</body>
</html>
Whether you need a custom integration or a full web application built around Formigo, our team at WorkersLab can help.
Built by WorkersLab LLC - Custom web applications that don't break