Recipes
Submit without leaving the page
Post with fetch and render your own confirmation.
The pattern behind every framework guide, without a framework. Three things matter: prevent the default navigation, send Accept: application/json, and read success from the response.
contact.html
<form>
<input type="text" name="name" required>
<input type="email" name="email" required>
<textarea name="message" required></textarea>
<button type="submit">Send</button>
</form>
<p id="status" role="status"></p>contact.js
const form = document.querySelector("form");
const status = document.querySelector("#status");
form.addEventListener("submit", async (event) => {
event.preventDefault();
status.textContent = "Sending…";
const body = new FormData(form);
try {
const res = await fetch("https://submit.formemailapi.com/YOUR_FORM_ID", {
method: "POST",
headers: { Accept: "application/json" },
body,
});
const result = await res.json();
status.textContent = result.message;
if (result.success) form.reset();
} catch {
// Network failure, not a rejected submission — say so honestly.
status.textContent = "Could not reach the server. Please try again.";
}
});Posting FormData rather than JSON is deliberate: it carries files, and it keeps repeated field names (checkbox groups) that JSON.stringify would silently collapse.
AJAX contact form exampleThe same pattern with a confirmation that replaces the form, and the two failure modes fetch reports differently.