Order form template
The product list is Starter kit, Custom bundle and Wholesale. Replace those words with your real products. You can put a price in the label, such as “Starter kit, 25 USD”. The value that arrives is the label text, so write the name you want to read in Telegram.
Quantity is type="number". Set a minimum in your page if you want to block zero. The sample does not set min for you.
Fields, no AI
Live preview
Preview only. Nothing is sent from this page.
Place an order
Copy the code
Replace fk_your_access_key with your own Formgong access key. The placeholder does not accept submissions. The honeypot field is named botcheck. Leave it empty.
The HTML form posts in the browser. React and Vue show an error on the page if the request fails. These class names need Tailwind on your site. This page does not load Tailwind. Bootstrap 5 class names need Bootstrap on your site. This page does not load Bootstrap.
<style>
#fg-fk_your_access_key{box-sizing:border-box;max-width:520px;width:100%;padding:28px;border:1px solid #dbe2ea;border-radius:8px;background:#fff;color:#0f172a;font:16px/1.5 system-ui,sans-serif;display:grid;gap:16px}#fg-fk_your_access_key *{box-sizing:border-box}#fg-fk_your_access_key h2{font-size:24px;line-height:1.3;margin:0 0 4px;color:#0f172a}#fg-fk_your_access_key label{display:grid;gap:6px;font-weight:500}#fg-fk_your_access_key input,#fg-fk_your_access_key textarea,#fg-fk_your_access_key select{width:100%;font:inherit;min-height:44px;border:1px solid #94a3b8;border-radius:8px;padding:10px 12px;background:#fff;color:#0f172a}#fg-fk_your_access_key textarea{min-height:96px;resize:vertical}#fg-fk_your_access_key .fg-reminder-consent{display:flex;align-items:flex-start;gap:10px;font-weight:400}#fg-fk_your_access_key input[type=checkbox]{width:20px;min-height:20px;flex-shrink:0;margin:2px 0}#fg-fk_your_access_key button{font:inherit;font-weight:600;min-height:48px;padding:12px 20px;border:0;border-radius:8px;background:#4338ca;color:#fff;cursor:pointer}#fg-fk_your_access_key :focus-visible{outline:3px solid #4338ca;outline-offset:3px}#fg-fk_your_access_key button:disabled{cursor:wait;opacity:.7}#fg-fk_your_access_key p{margin:0}#fg-fk_your_access_key fieldset{border:0;padding:0;margin:0;display:grid;gap:8px;min-width:0}#fg-fk_your_access_key legend{font-weight:500;padding:0;margin-bottom:6px}#fg-fk_your_access_key .fg-choice{display:flex;align-items:center;gap:10px;font-weight:400}#fg-fk_your_access_key input[type=radio]{width:20px;min-height:20px;flex-shrink:0;margin:0}#fg-fk_your_access_key .fg-trap{position:absolute;inset-inline-start:0;top:0;width:1px;height:1px;overflow:hidden;clip-path:inset(50%)}
</style>
<form id="fg-fk_your_access_key" action="https://formgong.com/submit" method="POST">
<h2>Place an order</h2>
<input type="hidden" name="access_key" value="fk_your_access_key">
<input type="hidden" name="_lang" value="en">
<label>Name * <input type="text" name="name" required autocomplete="name"></label>
<label>Email * <input type="email" name="email" required autocomplete="email"></label>
<label>Phone <input type="tel" name="phone" autocomplete="tel"></label>
<label>Product * <select name="product" required><option value="">—</option><option value="Starter kit">Starter kit</option><option value="Custom bundle">Custom bundle</option><option value="Wholesale">Wholesale</option></select></label>
<label>Quantity * <input type="number" name="quantity" required></label>
<label>Shipping address * <textarea name="shipping_address" required></textarea></label>
<label>Order notes <textarea name="notes"></textarea></label>
<div class="fg-trap" aria-hidden="true"><label>Leave this field empty<input name="botcheck" tabindex="-1" autocomplete="off"></label></div>
<button type="submit">Send order</button>
</form><form class="relative mx-auto grid w-full max-w-lg gap-4 rounded-lg border border-slate-200 bg-white p-6 text-base text-slate-900" action="https://formgong.com/submit" method="POST"> <h2 class="text-2xl font-semibold">Place an order</h2> <input type="hidden" name="access_key" value="fk_your_access_key"> <input type="hidden" name="_lang" value="en"> <div class="grid gap-1"><label class="font-medium" for="tw-name">Name *</label><input class="w-full rounded-md border border-slate-400 bg-white px-3 py-2 text-base text-slate-900 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-700" id="tw-name" type="text" name="name" autocomplete="name" required></div> <div class="grid gap-1"><label class="font-medium" for="tw-email">Email *</label><input class="w-full rounded-md border border-slate-400 bg-white px-3 py-2 text-base text-slate-900 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-700" id="tw-email" type="email" name="email" autocomplete="email" required></div> <div class="grid gap-1"><label class="font-medium" for="tw-phone">Phone</label><input class="w-full rounded-md border border-slate-400 bg-white px-3 py-2 text-base text-slate-900 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-700" id="tw-phone" type="tel" name="phone" autocomplete="tel"></div> <div class="grid gap-1"><label class="font-medium" for="tw-product">Product *</label><select class="w-full rounded-md border border-slate-400 bg-white px-3 py-2 text-base text-slate-900 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-700" id="tw-product" name="product" required><option value="">Choose</option><option value="Starter kit">Starter kit</option><option value="Custom bundle">Custom bundle</option><option value="Wholesale">Wholesale</option></select></div> <div class="grid gap-1"><label class="font-medium" for="tw-quantity">Quantity *</label><input class="w-full rounded-md border border-slate-400 bg-white px-3 py-2 text-base text-slate-900 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-700" id="tw-quantity" type="number" name="quantity" required></div> <div class="grid gap-1"><label class="font-medium" for="tw-shipping_address">Shipping address *</label><textarea class="w-full rounded-md border border-slate-400 bg-white px-3 py-2 text-base text-slate-900 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-700 min-h-24" id="tw-shipping_address" name="shipping_address" required></textarea></div> <div class="grid gap-1"><label class="font-medium" for="tw-notes">Order notes</label><textarea class="w-full rounded-md border border-slate-400 bg-white px-3 py-2 text-base text-slate-900 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-700 min-h-24" id="tw-notes" name="notes"></textarea></div> <div class="absolute start-0 top-0 h-px w-px overflow-hidden" aria-hidden="true"><label>Leave this empty<input name="botcheck" tabindex="-1" autocomplete="off"></label></div> <button class="min-h-12 rounded-md bg-indigo-700 px-4 py-3 font-semibold text-white" type="submit">Send order</button> </form>
<form class="position-relative mx-auto" style="max-width:32rem" action="https://formgong.com/submit" method="POST"> <h2 class="h4 mb-3">Place an order</h2> <input type="hidden" name="access_key" value="fk_your_access_key"> <input type="hidden" name="_lang" value="en"> <div class="mb-3"><label class="form-label" for="bs-name">Name *</label><input class="form-control" id="bs-name" type="text" name="name" autocomplete="name" required></div> <div class="mb-3"><label class="form-label" for="bs-email">Email *</label><input class="form-control" id="bs-email" type="email" name="email" autocomplete="email" required></div> <div class="mb-3"><label class="form-label" for="bs-phone">Phone</label><input class="form-control" id="bs-phone" type="tel" name="phone" autocomplete="tel"></div> <div class="mb-3"><label class="form-label" for="bs-product">Product *</label><select class="form-select" id="bs-product" name="product" required><option value="">Choose</option><option value="Starter kit">Starter kit</option><option value="Custom bundle">Custom bundle</option><option value="Wholesale">Wholesale</option></select></div> <div class="mb-3"><label class="form-label" for="bs-quantity">Quantity *</label><input class="form-control" id="bs-quantity" type="number" name="quantity" required></div> <div class="mb-3"><label class="form-label" for="bs-shipping_address">Shipping address *</label><textarea class="form-control" id="bs-shipping_address" name="shipping_address" rows="4" required></textarea></div> <div class="mb-3"><label class="form-label" for="bs-notes">Order notes</label><textarea class="form-control" id="bs-notes" name="notes" rows="4"></textarea></div> <div class="position-absolute top-0 start-0 overflow-hidden" style="width:1px;height:1px" aria-hidden="true"><label>Leave this empty<input name="botcheck" tabindex="-1" autocomplete="off"></label></div> <button class="btn btn-primary" type="submit">Send order</button> </form>
import { useEffect, useRef, useState } from "react";
// Visitor language for Formgong messages, thank-you text and autoreply.
const LANG = "en";
export default function ContactForm() {
const captcha = useRef(null);
const feedback = useRef(null);
const [failed, setFailed] = useState(false);
const [busy, setBusy] = useState(false);
const [status, setStatus] = useState("");
useEffect(() => mountCaptcha(captcha.current, null), []);
useEffect(() => { if (failed && status) feedback.current?.focus(); }, [failed, status]);
async function onSubmit(event) {
event.preventDefault();
if (busy) return;
const form = event.currentTarget;
const body = new FormData(form);
body.set("access_key", "fk_your_access_key");
body.set("_lang", LANG);
setBusy(true);
setFailed(false);
setStatus("Sending…");
try {
const response = await fetch("https://formgong.com/submit", {
method: "POST", headers: { Accept: "application/json" }, body,
});
const result = await response.json();
setFailed(!result.success);
setStatus(result.success ? (result.message || "Sent. Thank you!") : (result.message || "Could not send. Please try again."));
} catch { setFailed(true); setStatus("Connection failed. Please try again."); }
finally { setBusy(false); resetCaptcha(form); }
}
return <form id="fg-fk_your_access_key" onSubmit={onSubmit} aria-busy={busy}>
<style>{"#fg-fk_your_access_key{box-sizing:border-box;max-width:520px;width:100%;padding:28px;border:1px solid #dbe2ea;border-radius:8px;background:#fff;color:#0f172a;font:16px/1.5 system-ui,sans-serif;display:grid;gap:16px}#fg-fk_your_access_key *{box-sizing:border-box}#fg-fk_your_access_key h2{font-size:24px;line-height:1.3;margin:0 0 4px;color:#0f172a}#fg-fk_your_access_key label{display:grid;gap:6px;font-weight:500}#fg-fk_your_access_key input,#fg-fk_your_access_key textarea,#fg-fk_your_access_key select{width:100%;font:inherit;min-height:44px;border:1px solid #94a3b8;border-radius:8px;padding:10px 12px;background:#fff;color:#0f172a}#fg-fk_your_access_key textarea{min-height:96px;resize:vertical}#fg-fk_your_access_key .fg-reminder-consent{display:flex;align-items:flex-start;gap:10px;font-weight:400}#fg-fk_your_access_key input[type=checkbox]{width:20px;min-height:20px;flex-shrink:0;margin:2px 0}#fg-fk_your_access_key button{font:inherit;font-weight:600;min-height:48px;padding:12px 20px;border:0;border-radius:8px;background:#4338ca;color:#fff;cursor:pointer}#fg-fk_your_access_key :focus-visible{outline:3px solid #4338ca;outline-offset:3px}#fg-fk_your_access_key button:disabled{cursor:wait;opacity:.7}#fg-fk_your_access_key p{margin:0}#fg-fk_your_access_key fieldset{border:0;padding:0;margin:0;display:grid;gap:8px;min-width:0}#fg-fk_your_access_key legend{font-weight:500;padding:0;margin-bottom:6px}#fg-fk_your_access_key .fg-choice{display:flex;align-items:center;gap:10px;font-weight:400}#fg-fk_your_access_key input[type=radio]{width:20px;min-height:20px;flex-shrink:0;margin:0}#fg-fk_your_access_key .fg-trap{position:absolute;inset-inline-start:0;top:0;width:1px;height:1px;overflow:hidden;clip-path:inset(50%)}"}</style>
<h2>{"Place an order"}</h2>
<label>{"Name"} * <input type="text" name="name" required autoComplete="name" /></label>
<label>{"Email"} * <input type="email" name="email" required autoComplete="email" /></label>
<label>{"Phone"} <input type="tel" name="phone" autoComplete="tel" /></label>
<label>{"Product"} * <select name="product" required><option value="">—</option><option value={"Starter kit"}>{"Starter kit"}</option><option value={"Custom bundle"}>{"Custom bundle"}</option><option value={"Wholesale"}>{"Wholesale"}</option></select></label>
<label>{"Quantity"} * <input type="number" name="quantity" required /></label>
<label>{"Shipping address"} * <textarea name="shipping_address" required /></label>
<label>{"Order notes"} <textarea name="notes" /></label>
<div aria-hidden="true" style={{position:"absolute",insetInlineStart:0,top:0,width:1,height:1,overflow:"hidden",clipPath:"inset(50%)"}}><input name="botcheck" tabIndex={-1} autoComplete="off" /></div>
<button type="submit" disabled={busy}>{busy ? "Sending…" : "Send order"}</button>
<p ref={feedback} role="status" tabIndex={-1}>{status}</p>
</form>;
}
function mountCaptcha(node, siteKey) {
if (!node || !siteKey) return () => {};
let disposed = false;
let widget;
function render() {
if (disposed || !window.turnstile) return;
window.turnstile.ready(() => {
if (disposed) return;
widget = window.turnstile.render(node, { sitekey: siteKey, language: node.dataset.language || document.documentElement.lang || "auto" });
node.dataset.widgetId = widget;
});
}
if (window.turnstile) render();
else {
let script = document.querySelector('script[src^="https://challenges.cloudflare.com/turnstile/v0/api.js"]');
if (!script) {
script = document.createElement("script");
script.src = "https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit";
script.async = true;
document.head.appendChild(script);
}
script.addEventListener("load", render, { once: true });
}
return () => { disposed = true; if (widget !== undefined) window.turnstile?.remove(widget); };
}
function resetCaptcha(form) {
const widget = form.querySelector("[data-turnstile]")?.dataset.widgetId;
if (widget !== undefined) window.turnstile?.reset(widget);
}<script setup>
import { ref } from "vue";
const status = ref("");
const busy = ref(false);
async function onSubmit(event) {
const form = event.currentTarget;
if (busy.value || !form.reportValidity()) return;
const body = new FormData(form);
body.set("access_key", "fk_your_access_key");
body.set("_lang", "en");
busy.value = true;
status.value = "Sending…";
try {
const response = await fetch("https://formgong.com/submit", {
method: "POST",
headers: { Accept: "application/json" },
body,
});
const result = await response.json();
status.value = result.success ? (result.message || "Sent. Thank you!") : (result.message || "Could not send. Please try again.");
} catch {
status.value = "Connection failed. Please try again.";
} finally {
busy.value = false;
}
}
</script>
<template>
<form style="position:relative;display:grid;gap:16px;max-width:32rem" @submit.prevent="onSubmit" :aria-busy="busy">
<h2>Place an order</h2>
<label>Name * <input type="text" name="name" required autocomplete="name"></label>
<label>Email * <input type="email" name="email" required autocomplete="email"></label>
<label>Phone <input type="tel" name="phone" autocomplete="tel"></label>
<label>Product * <select name="product" required><option value="">—</option><option value="Starter kit">Starter kit</option><option value="Custom bundle">Custom bundle</option><option value="Wholesale">Wholesale</option></select></label>
<label>Quantity * <input type="number" name="quantity" required></label>
<label>Shipping address * <textarea name="shipping_address" required></textarea></label>
<label>Order notes <textarea name="notes"></textarea></label>
<div aria-hidden="true" style="position:absolute;inset-inline-start:0;top:0;width:1px;height:1px;overflow:hidden;clip-path:inset(50%)"><input name="botcheck" tabindex="-1" autocomplete="off"></div>
<button type="submit" :disabled="busy">Send order</button>
<p role="status" tabindex="-1">{{ status }}</p>
</form>
</template>Create a free form, then open Connect on that form in this browser. If it still has the default name, email and message fields, they are replaced with this form.
| This page | Poper order form generator | |
|---|---|---|
| Total | You add it, or leave it off | Live total, tax and currency |
| Payment | None. No card fields | Code you host yourself |
| Delivery | Telegram and email via Formgong | The generated code has no inbox |
| Account | None to copy | None, on their page |
Fields an order form needs
- Who. Name and email are required. Phone is optional, for a courier question.
- What. One product select. For two products, add a second select in the manual builder, or ask them to send a second order. This template is one line, not a cart.
- How many. A number field. You multiply by the price. The form does not.
- Where. Shipping address is a textarea. Ask for street, city, postal code and country in the placeholder if you add one later.
- Notes. Gift wrap, a delivery window, or a size. Optional.
A shop with a cart, stock and card checkout should use that shop. Shopify and a payment link win there. This template is for a baker, a small wholesale list, or a maker who takes a few orders by hand.
A running total, if you want one
Poper’s order form generator writes a live total, tax and currency. This page does not, because a wrong total on a public form is worse than no total. You can add a total yourself. Give each option a data-price and read it when the quantity changes. The script below is an example. It is not loaded on this page.
Optional total script
const form = document.querySelector("#order-form");
const total = form.querySelector("[data-total]");
function paint() {
const option = form.querySelector("[name=product]").selectedOptions[0];
const price = Number(option?.dataset.price || 0);
const qty = Number(form.querySelector("[name=quantity]").value || 0);
total.textContent = (price * qty).toFixed(2);
}
form.addEventListener("input", paint);
Put the currency in the page next to the total so the buyer knows it is not a charge. Formgong still receives the product name and the quantity, not a card number. Do not add card fields.
Order forms this template fits
- A weekend bakery. List the cakes. Quantity is how many. Notes are the inscription. You reply with a payment link.
- A wholesale request. The Wholesale option plus the address is enough for a first email. You send a real invoice from your books, not from this form.
- A custom bundle. The buyer picks Custom bundle and explains it in the notes. You quote a price. The form did not invent one.
Free limits, email and storage
The order form template is free to copy. An order is delivered only after you replace the placeholder key.
Copying the code needs no account. AI generations are limited to 5 an hour and 10 a day for each network, plus 100 a day for the whole site. When a limit is hit, use “Build it yourself, without AI”. That path does not call the model.
On the free plan, Telegram is instant and email is sent for every submission. The free plan is 300 submissions a month. Auto-reply is not on the free plan. Submission data is stored in the EU. Support is Formgong at support@formgong.com.
Your description is sent to the model so it can choose fields. It is not stored. Do not paste passwords, card numbers or other secrets.
Questions
What is an order form generator?
It builds a form for a product, a quantity and a shipping address, and gives you the HTML. This page loads that template. It does not run a shop.
Is there a free order form template?
Yes. The HTML on this page is the template. Copy it, change the product names, and replace fk_your_access_key. No account is required to copy.
Can the form charge a card?
No. Do not collect card numbers in these fields. Send a payment link after you accept the order, or use a shop that handles cards.
Will the total be calculated?
Not in the default copy. Option labels can show a price. An optional script on this page shows one way to multiply price by quantity in the browser. Formgong stores the fields you submit, not a computed total.
Where does the order arrive?
In the Formgong inbox after you add a real key. On the free plan, Telegram is instant and email is sent for every order.
Sources
Checked on 11.10.2026 against these public pages: FormBackend order form generator, Poper order form generator, splitforms order form template, MDN: input type=number.