Waitlist form template
Email, name and what they would use it for — a launch list that tells you who is waiting.
Reviewed by Ritu Fadadu · Last reviewed
Preview and code
Preview
Code — replace YOUR_ENDPOINT_ID with your form's ID
<style>
.fb-form { display: grid; gap: 1rem; max-width: 36rem; }
.fb-field { display: flex; flex-direction: column; gap: 0.375rem; }
.fb-fieldset { margin: 0; padding: 0; border: 0; min-width: 0; }
.fb-label { font-weight: 600; }
.fb-optional { font-weight: 400; color: #6b7280; }
.fb-help { margin: 0; font-size: 0.875rem; color: #6b7280; }
.fb-input { box-sizing: border-box; width: 100%; padding: 0.625rem 0.75rem; border: 1px solid #d1d5db; border-radius: 0.5rem; background: #fff; color: #111827; font: inherit; }
.fb-input:focus { border-color: #2563eb; outline: 2px solid #2563eb; outline-offset: 1px; }
.fb-options { display: flex; flex-direction: column; gap: 0.5rem; }
.fb-option { display: flex; align-items: center; gap: 0.5rem; }
.fb-check { width: 1.125rem; height: 1.125rem; margin: 0; accent-color: #2563eb; }
.fb-button { justify-self: start; min-height: 44px; padding: 0.625rem 1.25rem; border: 0; border-radius: 0.5rem; background: #2563eb; color: #fff; font: inherit; font-weight: 600; cursor: pointer; }
.fb-button:hover { background: #1d4ed8; }
.fb-button:focus-visible { outline: 2px solid #2563eb; outline-offset: 2px; }
.fb-button:disabled { opacity: 0.6; cursor: wait; }
.fb-status { margin: 0; min-height: 1.5em; }
@media (min-width: 640px) {
.fb-form { grid-template-columns: 1fr 1fr; }
.fb-field, .fb-button, .fb-status { grid-column: 1 / -1; }
.fb-field--half { grid-column: auto; }
}
</style>
<form id="fb-form" class="fb-form" action="https://formboost.app/f/YOUR_ENDPOINT_ID" method="POST">
<div class="fb-field">
<label for="fb-email" class="fb-label">Email</label>
<input type="email" id="fb-email" name="email" class="fb-input" required autocomplete="email">
</div>
<div class="fb-field fb-field--half">
<label for="fb-name" class="fb-label">Name <span class="fb-optional">(optional)</span></label>
<input type="text" id="fb-name" name="name" class="fb-input" autocomplete="name">
</div>
<div class="fb-field fb-field--half">
<label for="fb-company" class="fb-label">
Company
<span class="fb-optional">(optional)</span>
</label>
<input type="text" id="fb-company" name="company" class="fb-input" autocomplete="organization">
</div>
<div class="fb-field">
<label for="fb-use_case" class="fb-label">
What would you use it for?
<span class="fb-optional">(optional)</span>
</label>
<select id="fb-use_case" name="use_case" class="fb-input">
<option value="">Choose…</option>
<option value="personal-project">Personal project</option>
<option value="work">Work</option>
<option value="client-work">Client work</option>
<option value="just-curious">Just curious</option>
</select>
</div>
<div class="fb-field">
<label class="fb-option">
<input type="checkbox" id="fb-consent" name="consent" value="yes" class="fb-check" required>
<span>Email me when it's ready</span>
</label>
</div>
<input type="hidden" name="source" value="homepage">
<!-- Honeypot: keep it hidden. People never see it; bots fill it in and get flagged as spam. -->
<div
aria-hidden="true"
style="position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden"
>
<label for="fb-honey">Leave this field empty</label>
<input type="text" id="fb-honey" name="_honey" tabindex="-1" autocomplete="off">
</div>
<input type="hidden" name="_subject" value="New waitlist signup">
<button type="submit" class="fb-button">Join the waitlist</button>
</form>
<style>
.fb-form { display: grid; gap: 1rem; max-width: 36rem; }
.fb-field { display: flex; flex-direction: column; gap: 0.375rem; }
.fb-fieldset { margin: 0; padding: 0; border: 0; min-width: 0; }
.fb-label { font-weight: 600; }
.fb-optional { font-weight: 400; color: #6b7280; }
.fb-help { margin: 0; font-size: 0.875rem; color: #6b7280; }
.fb-input { box-sizing: border-box; width: 100%; padding: 0.625rem 0.75rem; border: 1px solid #d1d5db; border-radius: 0.5rem; background: #fff; color: #111827; font: inherit; }
.fb-input:focus { border-color: #2563eb; outline: 2px solid #2563eb; outline-offset: 1px; }
.fb-options { display: flex; flex-direction: column; gap: 0.5rem; }
.fb-option { display: flex; align-items: center; gap: 0.5rem; }
.fb-check { width: 1.125rem; height: 1.125rem; margin: 0; accent-color: #2563eb; }
.fb-button { justify-self: start; min-height: 44px; padding: 0.625rem 1.25rem; border: 0; border-radius: 0.5rem; background: #2563eb; color: #fff; font: inherit; font-weight: 600; cursor: pointer; }
.fb-button:hover { background: #1d4ed8; }
.fb-button:focus-visible { outline: 2px solid #2563eb; outline-offset: 2px; }
.fb-button:disabled { opacity: 0.6; cursor: wait; }
.fb-status { margin: 0; min-height: 1.5em; }
@media (min-width: 640px) {
.fb-form { grid-template-columns: 1fr 1fr; }
.fb-field, .fb-button, .fb-status { grid-column: 1 / -1; }
.fb-field--half { grid-column: auto; }
}
</style>
<form id="fb-form" class="fb-form" action="https://formboost.app/f/YOUR_ENDPOINT_ID" method="POST">
<div class="fb-field">
<label for="fb-email" class="fb-label">Email</label>
<input type="email" id="fb-email" name="email" class="fb-input" required autocomplete="email">
</div>
<div class="fb-field fb-field--half">
<label for="fb-name" class="fb-label">Name <span class="fb-optional">(optional)</span></label>
<input type="text" id="fb-name" name="name" class="fb-input" autocomplete="name">
</div>
<div class="fb-field fb-field--half">
<label for="fb-company" class="fb-label">
Company
<span class="fb-optional">(optional)</span>
</label>
<input type="text" id="fb-company" name="company" class="fb-input" autocomplete="organization">
</div>
<div class="fb-field">
<label for="fb-use_case" class="fb-label">
What would you use it for?
<span class="fb-optional">(optional)</span>
</label>
<select id="fb-use_case" name="use_case" class="fb-input">
<option value="">Choose…</option>
<option value="personal-project">Personal project</option>
<option value="work">Work</option>
<option value="client-work">Client work</option>
<option value="just-curious">Just curious</option>
</select>
</div>
<div class="fb-field">
<label class="fb-option">
<input type="checkbox" id="fb-consent" name="consent" value="yes" class="fb-check" required>
<span>Email me when it's ready</span>
</label>
</div>
<input type="hidden" name="source" value="homepage">
<!-- Honeypot: keep it hidden. People never see it; bots fill it in and get flagged as spam. -->
<div
aria-hidden="true"
style="position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden"
>
<label for="fb-honey">Leave this field empty</label>
<input type="text" id="fb-honey" name="_honey" tabindex="-1" autocomplete="off">
</div>
<input type="hidden" name="_subject" value="New waitlist signup">
<button type="submit" class="fb-button">Join the waitlist</button>
<p class="fb-status" role="status" aria-live="polite" data-fb-status></p>
</form>
<script>
document.getElementById("fb-form").addEventListener("submit", async (event) => {
event.preventDefault();
const form = event.currentTarget;
const status = form.querySelector("[data-fb-status]");
const button = form.querySelector('button[type="submit"]');
const fields = new FormData(form);
// Formboost accepts JSON or url-encoded bodies, not multipart, so send JSON.
const data = Object.fromEntries(fields);
// Makes the notification email replyable; the address still shows in the field table.
if (data.email) data._replyto = data.email;
button.disabled = true;
status.textContent = "Sending…";
try {
const response = await fetch(form.action, {
method: "POST",
headers: { "Content-Type": "application/json", Accept: "application/json" },
body: JSON.stringify(data),
});
if (response.ok) {
form.reset();
status.textContent = "You're on the list — we'll email you at launch.";
} else if (response.status === 429) {
status.textContent = "Too many attempts. Please wait a minute and try again.";
} else {
status.textContent = "Something went wrong. Please try again.";
}
} catch {
status.textContent = "Could not send. Check your connection and try again.";
} finally {
button.disabled = false;
}
});
</script>
import { useState } from "react";
// Your form's endpoint, from the Formboost dashboard.
const ENDPOINT = "https://formboost.app/f/YOUR_ENDPOINT_ID";
export default function WaitlistForm() {
const [sending, setSending] = useState(false);
const [message, setMessage] = useState("");
async function handleSubmit(event) {
event.preventDefault();
const form = event.currentTarget;
const fields = new FormData(form);
// Formboost accepts JSON or url-encoded bodies, not multipart, so send JSON.
const data = Object.fromEntries(fields);
// Makes the notification email replyable; the address still shows in the field table.
if (data.email) data._replyto = data.email;
setSending(true);
setMessage("Sending…");
try {
const response = await fetch(ENDPOINT, {
method: "POST",
headers: { "Content-Type": "application/json", Accept: "application/json" },
body: JSON.stringify(data),
});
if (response.ok) {
form.reset();
setMessage("You're on the list — we'll email you at launch.");
} else if (response.status === 429) {
setMessage("Too many attempts. Please wait a minute and try again.");
} else {
setMessage("Something went wrong. Please try again.");
}
} catch {
setMessage("Could not send. Check your connection and try again.");
} finally {
setSending(false);
}
}
return (
<form
className="grid max-w-xl gap-4 sm:grid-cols-2"
action={ENDPOINT}
method="POST"
onSubmit={handleSubmit}
>
<div className="flex flex-col gap-1.5 sm:col-span-2">
<label htmlFor="fb-email" className="text-sm font-semibold text-gray-900">Email</label>
<input
type="email"
id="fb-email"
name="email"
className="w-full rounded-lg border border-gray-300 bg-white px-3 py-2.5 text-gray-900 focus:border-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-600/30"
required
autoComplete="email"
/>
</div>
<div className="flex flex-col gap-1.5">
<label htmlFor="fb-name" className="text-sm font-semibold text-gray-900">
Name
<span className="font-normal text-gray-500">(optional)</span>
</label>
<input
type="text"
id="fb-name"
name="name"
className="w-full rounded-lg border border-gray-300 bg-white px-3 py-2.5 text-gray-900 focus:border-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-600/30"
autoComplete="name"
/>
</div>
<div className="flex flex-col gap-1.5">
<label htmlFor="fb-company" className="text-sm font-semibold text-gray-900">
Company
<span className="font-normal text-gray-500">(optional)</span>
</label>
<input
type="text"
id="fb-company"
name="company"
className="w-full rounded-lg border border-gray-300 bg-white px-3 py-2.5 text-gray-900 focus:border-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-600/30"
autoComplete="organization"
/>
</div>
<div className="flex flex-col gap-1.5 sm:col-span-2">
<label htmlFor="fb-use_case" className="text-sm font-semibold text-gray-900">
What would you use it for?
<span className="font-normal text-gray-500">(optional)</span>
</label>
<select
id="fb-use_case"
name="use_case"
className="w-full rounded-lg border border-gray-300 bg-white px-3 py-2.5 text-gray-900 focus:border-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-600/30"
>
<option value="">Choose…</option>
<option value="personal-project">Personal project</option>
<option value="work">Work</option>
<option value="client-work">Client work</option>
<option value="just-curious">Just curious</option>
</select>
</div>
<div className="flex flex-col gap-1.5 sm:col-span-2">
<label className="flex items-center gap-2 text-gray-800">
<input
type="checkbox"
id="fb-consent"
name="consent"
value="yes"
className="h-4 w-4 accent-blue-600"
required
/>
<span>Email me when it's ready</span>
</label>
</div>
<input type="hidden" name="source" defaultValue="homepage" />
{/* Honeypot: keep it hidden. People never see it; bots fill it in and get flagged as spam. */}
<div
aria-hidden="true"
style={{ position: "absolute", left: "-9999px", width: "1px", height: "1px", overflow: "hidden" }}
>
<label htmlFor="fb-honey">Leave this field empty</label>
<input type="text" id="fb-honey" name="_honey" tabIndex={-1} autoComplete="off" />
</div>
<input type="hidden" name="_subject" defaultValue="New waitlist signup" />
<button
type="submit"
className="min-h-11 justify-self-start rounded-lg bg-blue-600 px-5 py-2.5 font-semibold text-white hover:bg-blue-700 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-600 disabled:opacity-60 sm:col-span-2"
disabled={sending}
>
Join the waitlist
</button>
<p className="min-h-6 text-sm text-gray-700 sm:col-span-2" role="status" aria-live="polite">
{message}
</p>
</form>
);
}
<form
id="fb-form"
class="grid max-w-xl gap-4 sm:grid-cols-2"
action="https://formboost.app/f/YOUR_ENDPOINT_ID"
method="POST"
>
<div class="flex flex-col gap-1.5 sm:col-span-2">
<label for="fb-email" class="text-sm font-semibold text-gray-900">Email</label>
<input
type="email"
id="fb-email"
name="email"
class="w-full rounded-lg border border-gray-300 bg-white px-3 py-2.5 text-gray-900 focus:border-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-600/30"
required
autocomplete="email"
>
</div>
<div class="flex flex-col gap-1.5">
<label for="fb-name" class="text-sm font-semibold text-gray-900">
Name
<span class="font-normal text-gray-500">(optional)</span>
</label>
<input
type="text"
id="fb-name"
name="name"
class="w-full rounded-lg border border-gray-300 bg-white px-3 py-2.5 text-gray-900 focus:border-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-600/30"
autocomplete="name"
>
</div>
<div class="flex flex-col gap-1.5">
<label for="fb-company" class="text-sm font-semibold text-gray-900">
Company
<span class="font-normal text-gray-500">(optional)</span>
</label>
<input
type="text"
id="fb-company"
name="company"
class="w-full rounded-lg border border-gray-300 bg-white px-3 py-2.5 text-gray-900 focus:border-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-600/30"
autocomplete="organization"
>
</div>
<div class="flex flex-col gap-1.5 sm:col-span-2">
<label for="fb-use_case" class="text-sm font-semibold text-gray-900">
What would you use it for?
<span class="font-normal text-gray-500">(optional)</span>
</label>
<select
id="fb-use_case"
name="use_case"
class="w-full rounded-lg border border-gray-300 bg-white px-3 py-2.5 text-gray-900 focus:border-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-600/30"
>
<option value="">Choose…</option>
<option value="personal-project">Personal project</option>
<option value="work">Work</option>
<option value="client-work">Client work</option>
<option value="just-curious">Just curious</option>
</select>
</div>
<div class="flex flex-col gap-1.5 sm:col-span-2">
<label class="flex items-center gap-2 text-gray-800">
<input
type="checkbox"
id="fb-consent"
name="consent"
value="yes"
class="h-4 w-4 accent-blue-600"
required
>
<span>Email me when it's ready</span>
</label>
</div>
<input type="hidden" name="source" value="homepage">
<!-- Honeypot: keep it hidden. People never see it; bots fill it in and get flagged as spam. -->
<div
aria-hidden="true"
style="position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden"
>
<label for="fb-honey">Leave this field empty</label>
<input type="text" id="fb-honey" name="_honey" tabindex="-1" autocomplete="off">
</div>
<input type="hidden" name="_subject" value="New waitlist signup">
<button
type="submit"
class="min-h-11 justify-self-start rounded-lg bg-blue-600 px-5 py-2.5 font-semibold text-white hover:bg-blue-700 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-600 disabled:opacity-60 sm:col-span-2"
>
Join the waitlist
</button>
</form>
About this template
A waitlist form should be almost as short as a newsletter signup, with one extra question that pays for itself: what would you use it for? The answers tell you who is waiting before launch, which is the best market research you will get for free.
Only the email and the consent to be emailed are required. Name and company are optional, and the use-case question is a dropdown rather than a text box, so it costs one click and the answers group cleanly in the CSV export.
Formboost collects and stores the list; it does not send your launch email. Export the list when you launch, or on Starter and above send each signup to your email tool as it arrives with a webhook or Zapier.
Fields in this template
| Field | Name | Type | Required | Why it is there |
|---|---|---|---|---|
email | Yes | Required, first, and the whole point. | ||
| Name | name | Short text | No | Optional, for a personal launch email. |
| Company | company | Short text | No | Optional, to spot business interest early. |
| What would you use it for? | use_case | Dropdown | No | Optional dropdown — free market research. |
| Email me when it's ready | consent | Checkbox | Yes | Required: explicit permission to email them at launch. |
| (hidden) | source | Hidden value | No | Hidden. Set it per page to see where interest comes from. |
Each name becomes a column in your dashboard and a row in the notification email. The hidden _honey field is the honeypot; _subject sets the email's subject line. Both are reserved fields and never appear in the field table.
Make it yours
- Rewrite the use-case options for your product — they are the most valuable answers on the form.
- Show a position-free success message; promising “you're number 312” needs a counter Formboost does not keep.
- Change
sourceper page or campaign to compare which launch page works best. - If you open access in waves, add a hidden
cohortvalue when you send the first invitations, so later signups can be told apart from the original list.
Where the submissions go
- Every signup is stored and can be exported to CSV for your launch email, on every plan.
- On Starter and above, add signups to your email tool as they arrive with a webhook, Zapier or n8n.
- Anything flagged as spam stays in the spam tab and is never forwarded, so bots do not pad your list.
Newsletter Signups: plans, destinations and a worked setup →
Before you publish it
- Create a form in the Formboost dashboard and replace
YOUR_ENDPOINT_IDwith its ID. - Pick one variant: HTML posts and reloads, HTML + JS and React send JSON with
fetch()and stay on the page. - For the plain HTML version, add a hidden
_redirectwith anhttps://thank-you page on the same site as the form — anything else falls back to Formboost's page. - Submit it once from the live page and check the submission in your dashboard. Every request is acknowledged, so the dashboard is the real test. Troubleshooting covers the rest.
More form templates
Newsletter signup form template
Email, first name, the topics they want, and consent that is a real choice.
Survey form template
Four question types — a 0–10 score, single choice, multiple choice and an open answer — in one page.
Enquiry form template
What they are asking about, how they would like an answer, and the question itself.
All form templates
Every template, in HTML, React and Tailwind.
Put the waitlist form live
Free forever: 500 submissions a month across 10 forms, no card.