Order forms · 5 fields
Order enquiry form template
For orders you confirm by hand: made-to-order goods, wholesale, local delivery. The customer says what they want and where it should go, and you reply with availability, the total and how to pay.
Product order
Live demo: try the fields. Submitting sends nothing.
02 / Field guide
Why these fields
Name
text · requiredRequired, to address the confirmation.
Email
email · requiredRequired. It is where the confirmation, the total and the payment link go.
Product
text · requiredFree text keeps the template generic. With a short fixed range, change it to a select so orders are consistent and easy to filter.
Quantity
number · requiredRequired. The generated markup is a plain number input, so add min="1" and the browser refuses zero and negative values.
Shipping address
textarea · requiredRequired because the template is for delivered goods. If customers collect, remove it: an address you do not need is data you have to protect.
When to use it
Use it where a checkout would be overkill or impossible: custom work, trade customers, small producers. It collects a request, it does not take payment.
If you sell a short fixed range, turn the product field into a select. For catering or bakery orders with a date, the bakery and catering templates fit better.
Privacy and GDPR
- Never take card details in this form. Send a payment link or an invoice after you confirm the order, through a payment provider.
- An enquiry and a sale have different lives. Once an order is confirmed, bookkeeping rules decide how long its record stays, so move it into your accounting or order system and let the form keep only open enquiries.
- Set the form's retention to cover your follow-up time, not your bookkeeping period.
03 / Make it yours
Choose your stack. Copy your form.
Replace the example endpoint with your Formward endpoint, then adapt the fields to your needs.
<form action="https://forms.formward.eu/f/your-form-id" method="POST">
<label for="name">Name</label>
<input type="text" name="name" id="name" required />
<label for="email">Email</label>
<input type="email" name="email" id="email" required />
<label for="product">Product</label>
<input type="text" name="product" id="product" required />
<label for="quantity">Quantity</label>
<input type="number" name="quantity" id="quantity" required />
<label for="shipping_address">Shipping address</label>
<textarea name="shipping_address" id="shipping_address" required></textarea>
<input type="text" name="_gotcha" tabindex="-1" autocomplete="off" style="position:absolute;left:-9999px" aria-hidden="true" />
<button type="submit">Send</button>
</form>Accessibility
Accessible by default, and how to keep it that way
- Every field in the code has a visible label tied to it with for and id, so screen readers announce what to enter and a click on the label focuses the field.
- Required fields carry the required attribute, so the browser explains a missing answer before anything is sent. Say “required” in words as well; an asterisk or a colour alone is easy to miss.
- The spam trap field (_gotcha) is hidden from screen readers with aria-hidden and skipped by the Tab key, so people never meet it.
- In the JavaScript versions, show the confirmation or error in an element with role="status" so the result is announced, and keep the entered answers when sending fails.
Changed the fields? Paste your version into the HTML form tester to see exactly what it sends, or run it through the GDPR form checker.
04 / Implementation
How the code talks to Formward
Each form you create gets its own endpoint in the form https://forms.formward.eu/f/your-form-id. The HTML version posts to it directly and the browser is redirected to a thank-you page, so it works without JavaScript.
The Next.js version below sends the same fields with fetch and an Accept: application/json header. Formward then answers with { ok: true, id }, or an error body with 402 when the plan limit is reached and 429 when the rate limit kicks in. See responses and status codes.
Next.js client component
"use client";
import { useState } from "react";
export function ProductOrderForm() {
const [sent, setSent] = useState(false);
async function onSubmit(e: React.FormEvent<HTMLFormElement>) {
e.preventDefault();
const form = e.currentTarget;
const res = await fetch("https://forms.formward.eu/f/your-form-id", {
method: "POST",
headers: { Accept: "application/json" },
body: new FormData(form),
});
if (res.ok) {
setSent(true);
form.reset();
}
}
if (sent) return <p>Thanks! Your message has been sent.</p>;
return (
<form onSubmit={onSubmit}>
<label htmlFor="name">Name</label>
<input type="text" name="name" id="name" required />
<label htmlFor="email">Email</label>
<input type="email" name="email" id="email" required />
<label htmlFor="product">Product</label>
<input type="text" name="product" id="product" required />
<label htmlFor="quantity">Quantity</label>
<input type="number" name="quantity" id="quantity" required />
<label htmlFor="shipping_address">Shipping address</label>
<textarea name="shipping_address" id="shipping_address" required />
<input
type="text"
name="_gotcha"
tabIndex={-1}
autoComplete="off"
style={{ position: "absolute", left: "-9999px" }}
aria-hidden="true"
/>
<button type="submit">Send</button>
</form>
);
}
Spam protection
- The generated code already includes the hidden _gotcha honeypot. Leave it in: a bot that fills it gets a normal success response, the submission is filed as spam and no email is sent.
- Every form has a per-IP rate limit, and you can restrict it to your own domains with the allowed-origins list in the form settings.
- Cloudflare Turnstile is optional and works on every plan, including Free. Turn it on in the form settings, add the widget to your markup and Formward checks the token server-side.
- The form settings can also reject disposable email addresses, which is worth turning on when a fake address would waste your time.
What happens after submit
- Each order request is emailed to you and stored in the EU on every plan, and CSV export starts at Personal.
- From Professional, the autoresponder can confirm receipt and say that the order is not final until you reply.
- From Professional, a webhook can create the order in your shop or order system automatically.
Questions
- Is submitting this form a binding order?
- Not unless you make it one. The template is written as a request: you confirm price, availability and payment afterwards. Say so next to the submit button so customers know what to expect.
- Can I use it on a Shopify store?
- Yes, for orders outside checkout, such as wholesale or custom work. The Shopify tab generates a section for your theme. Keep ordinary sales in Shopify's own checkout.
Related
- Order templates
Bakery, catering, T-shirt and change orders.
- Quote request template
When the price depends on the job.
- Shopify forms
Add a non-checkout form to a theme.
- Form to email
How each order reaches your inbox.
Customize before publishing
- Remove fields you do not need and mark only essential answers as required.
- Replace placeholder wording with terms your audience already understands.
- Add your privacy notice, retention details and expected response time.
- Test keyboard focus, validation errors and the confirmation state on mobile.
Use this template
Create a free account and the form is set up from this template. Copy your endpoint and replace https://forms.formward.eu/f/your-form-id in the code above.