Auth Forms
Verify email with resend timer
Waiting state with a cooling-off resend button
Waiting state with a cooling-off resend button
Create an email verification waiting screen with Tailwind CSS. Centre a max-w-sm card holding a neutral-tinted round tile with an envelope glyph, a heading reading "Check your inbox", and a line saying a verification link was sent to an address shown in medium weight with a small "change" link beside it. Add three muted hint rows with check glyphs — the link works once, it expires in an hour, and the tab can be closed once verified. Then a full-width outline "Resend email" button that starts disabled with a countdown in its label, a small muted line reporting how many times it has been sent, and a footer link to contact support. Then add JavaScript that starts a thirty second countdown, updates the button label each second, enables it when the countdown ends, and on click increments the send counter, updates the "sent" line and restarts the countdown from a longer interval each time. <div class="flex min-h-screen items-center justify-center bg-neutral-50 px-6 py-14">
<div class="w-full max-w-sm rounded-2xl border border-neutral-200 bg-white p-7 text-center shadow-sm">
<div class="mx-auto mb-5 grid h-12 w-12 place-items-center rounded-full bg-neutral-100 text-neutral-700"><svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" class="inline-block h-[1em] w-[1em] shrink-0 align-[-0.125em] transition-transform"><rect x="3" y="5" width="18" height="14" rx="2"/><path d="m4 7 8 6 8-6"/></svg></div>
<h1 class="text-lg font-semibold text-neutral-900">Check your inbox</h1>
<p class="mt-1.5 text-sm leading-relaxed text-neutral-500">
We sent a verification link to <span class="font-medium text-neutral-900">[email protected]</span>
<a href="#" class="ml-1 text-neutral-500 underline underline-offset-4 hover:text-neutral-900">change</a>
</p>
<ul class="mt-6 space-y-2 rounded-xl bg-neutral-50 p-4 text-left text-xs text-neutral-600">
<li class="flex items-start gap-2"><svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" class="inline-block h-[1em] w-[1em] shrink-0 align-[-0.125em] transition-transform"><path d="m5 12.5 4.25 4.25L19 7"/></svg> <span>The link signs you in once, then stops working.</span></li>
<li class="flex items-start gap-2"><svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" class="inline-block h-[1em] w-[1em] shrink-0 align-[-0.125em] transition-transform"><path d="m5 12.5 4.25 4.25L19 7"/></svg> <span>It expires 60 minutes after it was sent.</span></li>
<li class="flex items-start gap-2"><svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" class="inline-block h-[1em] w-[1em] shrink-0 align-[-0.125em] transition-transform"><path d="m5 12.5 4.25 4.25L19 7"/></svg> <span>You can close this tab — we will pick up where you left off.</span></li>
</ul>
<button id="resendBtn" disabled
class="mt-6 w-full cursor-not-allowed rounded-xl border border-neutral-200 py-2.5 text-sm font-medium text-neutral-400 transition">
Resend email in 30s
</button>
<p id="resendNote" class="mt-2 text-xs text-neutral-400">Sent once to this address.</p>
<p class="mt-6 border-t border-neutral-200 pt-4 text-xs text-neutral-400">
Nothing arrived? <a href="#" class="font-medium text-neutral-600 underline underline-offset-4 hover:text-neutral-900">Contact support</a>
</p>
</div>
</div> var btn = document.getElementById("resendBtn");
var note = document.getElementById("resendNote");
var sends = 1;
var wait = 30;
var left = wait;
var timer;
function label() {
btn.textContent = left > 0 ? "Resend email in " + left + "s" : "Resend email";
}
function lock(state) {
btn.disabled = state;
btn.classList.toggle("cursor-not-allowed", state);
btn.classList.toggle("text-neutral-400", state);
btn.classList.toggle("text-neutral-700", !state);
btn.classList.toggle("hover:bg-neutral-50", !state);
}
function countdown() {
clearInterval(timer);
left = wait;
label();
lock(true);
timer = setInterval(function () {
left -= 1;
label();
if (left <= 0) {
clearInterval(timer);
lock(false);
}
}, 1000);
}
btn.addEventListener("click", function () {
if (btn.disabled) return;
sends += 1;
note.textContent = "Sent " + sends + " times to this address.";
// Each retry costs a little more patience than the last.
wait = Math.min(wait * 2, 120);
countdown();
});
countdown();