Vercel doesn't include built-in form handling, so the simplest option is to post your form directly to a FormSubmit endpoint. You avoid writing a Vercel Function, configuring an email provider and storing submissions yourself.
Plain HTML / static sites
<form action="https://formsubmit.app/f/YOUR_FORM_ID" method="POST" class="mx-auto max-w-lg space-y-5">
<div class="space-y-1.5">
<label for="fs-name" class="block text-sm font-medium text-gray-900">Name</label>
<input id="fs-name" type="text" name="name" placeholder="Jane Doe" required class="block w-full rounded-lg border border-gray-300 px-3 py-2 text-sm shadow-sm focus:border-indigo-500 focus:outline-none focus:ring-2 focus:ring-indigo-500/20">
</div>
<div class="space-y-1.5">
<label for="fs-email" class="block text-sm font-medium text-gray-900">Email</label>
<input id="fs-email" type="email" name="email" placeholder="jane@example.com" required class="block w-full rounded-lg border border-gray-300 px-3 py-2 text-sm shadow-sm focus:border-indigo-500 focus:outline-none focus:ring-2 focus:ring-indigo-500/20">
</div>
<div class="space-y-1.5">
<label for="fs-message" class="block text-sm font-medium text-gray-900">Message</label>
<textarea id="fs-message" name="message" rows="5" placeholder="How can we help?" required class="block w-full rounded-lg border border-gray-300 px-3 py-2 text-sm shadow-sm focus:border-indigo-500 focus:outline-none focus:ring-2 focus:ring-indigo-500/20"></textarea>
</div>
<!-- Honeypot: leave this hidden field empty to catch bots -->
<input type="text" name="_gotcha" tabindex="-1" autocomplete="off" style="display:none">
<!-- Optional: where to send people after submitting -->
<!-- <input type="hidden" name="_redirect" value="https://yoursite.com/thanks"> -->
<button type="submit" class="inline-flex w-full items-center justify-center rounded-lg bg-gray-900 px-4 py-2.5 text-sm font-medium text-white hover:bg-gray-800 disabled:opacity-50">Send</button>
</form>Next.js on Vercel
Follow the Next.js contact form guide — it's a single client component and works with both dynamic and static (output: "export") builds.
Preview deployments
Every Vercel preview gets its own URL. Add *.vercel.app to the allowlist alongside your production domain so testing works on previews — or scope it tighter with your team's preview prefix.
Triggering your own code
Want to run logic in your app when a submission arrives (e.g. create a user in your database)? Add a webhook pointing at a route handler in your Next.js app and verify the signature. You get FormSubmit's spam filtering and retries in front of your code.