Next.js request a demo form
Add a request-a-demo form to your Next.js marketing site with no backend. Copy the code, preview it live, and qualified leads land in your inbox or Slack. No API route to build.
How to build it
- Create a form in your Formpaste dashboard and copy its access key.
- Copy the Next.js code into a client component and pick your styling.
- Replace YOUR_ACCESS_KEY_HERE with your access key, then deploy.
Prompt for your AI coding agent
Add a Formpaste request-a-demo form to my Next.js app. Use a client component with name, work email, company, team size and a message field that POSTs as application/x-www-form-urlencoded (URLSearchParams) to https://api.formpaste.com/submit with a hidden access_key input. Show a confirmation with next steps after the fetch resolves. Do not add an API route.Or connect the Formpaste MCP server to Claude Code, Codex, Cursor, Claude Desktop, VS Code, or any mcp-remote client. See the setup guide.
Next.js gotchas
Next.js gives you API routes, but for simpler forms, spinning up a route handler is overkill. Formpaste handles the backend so you can keep your Next.js app focused on the frontend. Works with both App Router and Pages Router.
Client component for the fetch version
The onSubmit fetch needs to run in the browser, so put the form in a file with "use client" at the top. A plain <form action> with a redirect works in a server component too if you do not need JS.
No API route needed
You do not need /api/contact. Posting straight to the Formpaste endpoint keeps the app static-friendly and deployable anywhere, including static export.
Server Actions are optional
You can wire a Server Action, but it is not required and adds a server round-trip. The direct POST is simpler and works on static hosting.
Edge runtime and file uploads
If a route uses the Edge runtime, multipart form data handling differs from Node. For file-upload forms, post directly to Formpaste from the client so your own runtime never parses the upload.
Static export friendly
Because the form posts to an external endpoint, output: export keeps working. No server code of yours runs at request time.
What to get right
Qualify without friction
Ask for company and work email so sales can prioritize, but keep the form short. Long forms lose qualified leads.
Route by field
Send demo requests to sales, and forward to Slack with a webhook so the team sees them immediately.
Confirm next steps
On success, tell the visitor what happens next and when to expect a reply.
How it works
Three simple steps for form submissions to land in your email inbox.
Create your form, set your form's action URL to Formpaste's endpoint, and add your access key.
Create your form
Sign up, verify your email, and create an access key in your dashboard.
Copy the code
Paste the snippet above into your project. Pick CSS or Tailwind to match your site.
export function ContactForm() {
async function onSubmit(e) {
e.preventDefault();
const form = new FormData(e.currentTarget);
await fetch("https://api.formpaste.com/submit", { method: "POST", body: new URLSearchParams(form) });
}
return (
<form onSubmit={onSubmit} className="mx-auto flex w-full max-w-md flex-col gap-4 rounded-xl border border-gray-200 bg-white p-6 shadow-sm dark:border-gray-800 dark:bg-gray-950">
<input type="hidden" name="access_key" value="YOUR_ACCESS_KEY_HERE" />
<label className="flex flex-col gap-1.5 text-sm font-medium text-gray-900 dark:text-gray-100">Name
<input type="text" name="name" required className="rounded-md border border-gray-300 bg-white px-3 py-2 text-sm text-gray-900 shadow-sm outline-none focus-visible:ring-2 focus-visible:ring-gray-900 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-100 dark:focus-visible:ring-gray-100" />
</label>
<label className="flex flex-col gap-1.5 text-sm font-medium text-gray-900 dark:text-gray-100">Work email
<input type="email" name="email" required className="rounded-md border border-gray-300 bg-white px-3 py-2 text-sm text-gray-900 shadow-sm outline-none focus-visible:ring-2 focus-visible:ring-gray-900 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-100 dark:focus-visible:ring-gray-100" />
</label>
<label className="flex flex-col gap-1.5 text-sm font-medium text-gray-900 dark:text-gray-100">Company
<input type="text" name="company" required className="rounded-md border border-gray-300 bg-white px-3 py-2 text-sm text-gray-900 shadow-sm outline-none focus-visible:ring-2 focus-visible:ring-gray-900 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-100 dark:focus-visible:ring-gray-100" />
</label>
<label className="flex flex-col gap-1.5 text-sm font-medium text-gray-900 dark:text-gray-100">Team size
<input type="text" name="team_size" className="rounded-md border border-gray-300 bg-white px-3 py-2 text-sm text-gray-900 shadow-sm outline-none focus-visible:ring-2 focus-visible:ring-gray-900 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-100 dark:focus-visible:ring-gray-100" />
</label>
<label className="flex flex-col gap-1.5 text-sm font-medium text-gray-900 dark:text-gray-100">What do you want to see?
<textarea name="message" className="min-h-28 rounded-md border border-gray-300 bg-white px-3 py-2 text-sm text-gray-900 shadow-sm outline-none focus-visible:ring-2 focus-visible:ring-gray-900 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-100 dark:focus-visible:ring-gray-100"></textarea>
</label>
<button type="submit" className="w-full rounded-md bg-gray-900 px-4 py-2 text-sm font-medium text-white shadow-sm transition-colors hover:bg-gray-800 disabled:opacity-60 dark:bg-white dark:text-gray-900 dark:hover:bg-gray-200">Request a demo</button>
</form>
);
}Add your access key
Replace the placeholder with your access key to start receiving submissions.
<input type="hidden" name="access_key" value="YOUR_ACCESS_KEY_HERE">Next.js request a demo form FAQ
Paste a form. Get submissions.
Instantly without setting up any backend, servers or databases. 250 submissions/mo free - no credit card.