Waitlist Signup Form
Collect pre-launch signups with a minimal email + name form. Build hype, capture intent, and message your audience on launch day.
Don't have one yet? Sign up now and get one in less than 5 minutes.
Add your Formtorch endpoint
Paste your form ID and the code below updates instantly.
<section class="ft-waitlist-demo" aria-label="Waitlist signup form demo">
<div class="ft-window">
<div class="ft-window-bar" aria-hidden="true">
<span></span>
<span></span>
<span></span>
</div>
<form id="waitlist-form" class="ft-form" accept-charset="UTF-8">
<div class="ft-icon" aria-hidden="true">
<svg viewBox="0 0 24 24">
<path
d="M4.5 16.5c-1.5 1.26-2 5-2 5s3.74-.5 5-2c.71-.84.7-2.13-.09-2.91a2.18 2.18 0 0 0-2.91-.09z"
/>
<path
d="m12 15-3-3a22 22 0 0 1 2-3.95A12.88 12.88 0 0 1 22 2c0 2.72-.78 7.5-6 11a22.35 22.35 0 0 1-4 2z"
/>
<path d="M9 12H4s.55-3.03 2-4c1.62-1.08 5 0 5 0" />
<path d="M12 15v5s3.03-.55 4-2c1.08-1.62 0-5 0-5" />
</svg>
</div>
<div class="ft-form-heading">
<h2>Join the waitlist</h2>
<p>
Be the first to try Formtorch. Get early access and launch updates.
</p>
</div>
<input type="hidden" name="_formName" value="Waitlist Signup" />
<div class="ft-field">
<div class="ft-control">
<svg aria-hidden="true" viewBox="0 0 24 24">
<path d="M4 6h16v12H4z" />
<path d="m4 7 8 6 8-6" />
</svg>
<input
id="ft-email"
type="email"
name="email"
placeholder="Enter your email"
aria-label="Email address"
autocomplete="email"
required
/>
</div>
</div>
<button class="ft-submit" type="submit">
<svg aria-hidden="true" viewBox="0 0 24 24">
<path d="m22 2-7 20-4-9-9-4Z" />
<path d="M22 2 11 13" />
</svg>
<span>Join Waitlist</span>
</button>
<p id="ft-status" class="ft-status" aria-live="polite"></p>
</form>
</div>
</section>
<style>
html,
body {
margin: 0;
padding: 0;
background: #05070d;
}
.ft-waitlist-demo {
position: relative;
box-sizing: border-box;
width: 100%;
min-height: 100vh;
padding: clamp(24px, 5vw, 64px);
display: grid;
place-items: center;
font-family:
Inter,
ui-sans-serif,
system-ui,
-apple-system,
BlinkMacSystemFont,
"Segoe UI",
sans-serif;
color: #f8fafc;
background:
radial-gradient(circle at 22% 18%, rgb(37 99 235 / 0.2), transparent 32%),
radial-gradient(
circle at 78% 75%,
rgb(37 99 235 / 0.18),
transparent 30%
),
#05070d;
}
.ft-waitlist-demo,
.ft-waitlist-demo * {
box-sizing: border-box;
}
.ft-waitlist-demo::before,
.ft-waitlist-demo::after {
content: "";
position: absolute;
z-index: 0;
width: clamp(90px, 16vw, 130px);
height: clamp(130px, 20vw, 190px);
pointer-events: none;
opacity: 0.45;
background-image: radial-gradient(
rgb(37 99 235 / 0.9) 1.5px,
transparent 1.5px
);
background-size: 20px 20px;
}
.ft-waitlist-demo::before {
top: 9%;
left: 5%;
}
.ft-waitlist-demo::after {
bottom: 9%;
right: 5%;
}
.ft-window {
position: relative;
z-index: 1;
width: min(100%, 460px);
overflow: hidden;
border: 1px solid rgb(148 163 184 / 0.22);
border-radius: 24px;
background:
linear-gradient(180deg, rgb(255 255 255 / 0.06), transparent 130px),
linear-gradient(145deg, rgb(15 23 42 / 0.96), rgb(2 6 23 / 0.96));
box-shadow:
0 26px 80px rgb(0 0 0 / 0.45),
0 0 0 1px rgb(255 255 255 / 0.04),
0 0 44px rgb(37 99 235 / 0.2);
}
.ft-window-bar {
position: relative;
z-index: 1;
height: 64px;
display: flex;
align-items: center;
gap: 12px;
padding: 0 32px;
border-bottom: 1px solid rgb(148 163 184 / 0.12);
background: rgb(255 255 255 / 0.025);
}
.ft-window-bar span {
width: 14px;
height: 14px;
border-radius: 999px;
background: #2563eb;
box-shadow: 0 0 20px rgb(37 99 235 / 0.55);
}
.ft-window-bar span:nth-child(2) {
background: #1d4ed8;
}
.ft-window-bar span:nth-child(3) {
background: #334155;
box-shadow: none;
}
.ft-form {
position: relative;
z-index: 1;
display: flex;
flex-direction: column;
align-items: center;
gap: 20px;
padding: clamp(32px, 6vw, 44px);
text-align: center;
}
.ft-icon {
display: flex;
align-items: center;
justify-content: center;
width: 60px;
height: 60px;
border-radius: 16px;
background: linear-gradient(
160deg,
rgb(37 99 235 / 0.22),
rgb(15 23 42 / 0.4)
);
border: 1px solid rgb(148 163 184 / 0.18);
box-shadow: 0 0 30px rgb(37 99 235 / 0.18);
}
.ft-icon svg {
width: 26px;
height: 26px;
color: #3b82f6;
fill: none;
stroke: currentColor;
stroke-width: 2;
stroke-linecap: round;
stroke-linejoin: round;
}
.ft-form-heading h2 {
margin: 0;
color: #f8fafc;
font-size: clamp(26px, 5vw, 32px);
line-height: 1.15;
letter-spacing: -0.03em;
}
.ft-form-heading p {
margin: 10px 0 0;
color: #94a3b8;
font-size: clamp(14px, 2.4vw, 15px);
line-height: 1.55;
max-width: 320px;
}
.ft-field {
width: 100%;
}
.ft-control {
position: relative;
display: flex;
align-items: center;
}
.ft-control svg {
position: absolute;
left: 18px;
width: 20px;
height: 20px;
color: #2563eb;
fill: none;
stroke: currentColor;
stroke-width: 2;
stroke-linecap: round;
stroke-linejoin: round;
pointer-events: none;
}
.ft-control input {
width: 100%;
height: 54px;
border: 1px solid rgb(148 163 184 / 0.24);
border-radius: 10px;
background: rgb(15 23 42 / 0.52);
color: #f8fafc;
font: inherit;
font-size: 16px;
padding: 0 18px 0 56px;
outline: none;
transition:
border-color 160ms ease,
background-color 160ms ease,
box-shadow 160ms ease;
}
.ft-control input::placeholder {
color: #64748b;
}
.ft-control input:hover {
border-color: rgb(148 163 184 / 0.38);
background: rgb(15 23 42 / 0.7);
}
.ft-control input:focus-visible {
border-color: #2563eb;
background: rgb(15 23 42 / 0.78);
box-shadow: 0 0 0 4px rgb(37 99 235 / 0.18);
}
.ft-submit {
appearance: none;
width: 100%;
height: 56px;
border: 0;
border-radius: 10px;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 12px;
padding: 0 22px;
background: linear-gradient(135deg, #3b82f6, #1d4ed8);
color: #fff;
font: inherit;
font-size: 16px;
font-weight: 650;
cursor: pointer;
box-shadow:
inset 0 1px 0 rgb(255 255 255 / 0.2),
0 16px 34px rgb(37 99 235 / 0.18);
transition:
transform 160ms ease,
filter 160ms ease,
box-shadow 160ms ease;
}
.ft-submit svg {
width: 20px;
height: 20px;
fill: none;
stroke: currentColor;
stroke-width: 2;
stroke-linecap: round;
stroke-linejoin: round;
}
.ft-submit:hover {
filter: brightness(1.05);
box-shadow:
inset 0 1px 0 rgb(255 255 255 / 0.22),
0 20px 42px rgb(37 99 235 / 0.24);
}
.ft-submit:active {
transform: translateY(1px);
}
.ft-submit:focus-visible {
outline: none;
box-shadow:
0 0 0 4px rgb(37 99 235 / 0.22),
0 20px 42px rgb(37 99 235 / 0.24);
}
.ft-submit:disabled {
cursor: not-allowed;
opacity: 0.65;
filter: grayscale(0.15);
}
.ft-status {
min-height: 24px;
margin: 0;
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
color: #94a3b8;
font-size: 14px;
line-height: 1.4;
}
.ft-status svg {
width: 17px;
height: 17px;
flex: 0 0 auto;
fill: none;
stroke: currentColor;
stroke-width: 2;
stroke-linecap: round;
stroke-linejoin: round;
}
.ft-status[data-state="success"] {
color: #22c55e;
}
.ft-status[data-state="error"] {
color: #f87171;
}
@media (max-width: 480px) {
.ft-waitlist-demo {
padding: 18px;
}
.ft-waitlist-demo::before,
.ft-waitlist-demo::after {
display: none;
}
.ft-window {
border-radius: 20px;
}
.ft-window-bar {
height: 54px;
padding: 0 22px;
}
.ft-form {
gap: 16px;
padding: 28px 22px;
}
.ft-control input {
height: 50px;
}
.ft-submit {
height: 52px;
}
}
</style>
<script>
const form = document.getElementById("waitlist-form");
const status = document.getElementById("ft-status");
const button = form.querySelector("button[type='submit']");
const buttonLabel = button.querySelector("span");
const successIcon =
'<svg aria-hidden="true" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"></circle><path d="m9 12 2 2 4-4"></path></svg>';
const errorIcon =
'<svg aria-hidden="true" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"></circle><path d="m15 9-6 6"></path><path d="m9 9 6 6"></path></svg>';
form.addEventListener("submit", async (event) => {
event.preventDefault();
status.innerHTML = "";
status.removeAttribute("data-state");
button.disabled = true;
buttonLabel.textContent = "Joining...";
try {
const response = await fetch("https://formtorch.com/f/abc123", {
method: "POST",
headers: {
"X-Requested-With": "XMLHttpRequest",
Accept: "application/json",
},
body: new FormData(form),
});
if (!response.ok) {
throw new Error("Submission failed");
}
form.reset();
status.dataset.state = "success";
status.innerHTML = successIcon + "<span>You're on the list.</span>";
buttonLabel.textContent = "Join Waitlist";
} catch {
status.dataset.state = "error";
status.innerHTML =
errorIcon + "<span>Something went wrong. Please try again.</span>";
buttonLabel.textContent = "Try again";
} finally {
button.disabled = false;
}
});
</script>
Why Use This Template
What is a waitlist signup form?
A waitlist signup form collects a name and email from visitors who want early access to a product that hasn't launched yet. It's the standard way to capture demand on a coming-soon or pre-launch landing page.
Why do you need a waitlist form before launch?
A waitlist turns interest into a list you can message the day you launch, instead of hoping visitors come back on their own. It also gives you a real number: how many people actually want the thing you're building, before you build all of it.
How do you add a waitlist form with a backend like Formtorch?
Paste the markup into your landing page and connect the action attribute to your Formtorch endpoint: no account system or database required to start collecting signups. Every submission lands in your dashboard, ready to message when you're ready to launch.
Related read: how to send a confirmation email the moment someone signs up
How it works
Create a Formtorch endpoint
Sign up and create a new form endpoint in the dashboard. You will get a unique URL in seconds.
Create endpointPaste it into your form
Set your form's action attribute to your endpoint URL. No other changes required.
Deploy and start receiving submissions
Every submission is stored in your dashboard, triggers email notifications, and can fire webhooks to any service.
Frequently asked questions
No. Formtorch works with standard HTML forms via the action attribute. No JavaScript required for basic submissions.
Start in less than 5 minutes
Create your endpoint, paste it into any template, and you are live.