Where this goes
Save this as app/contact/Contact.tsx. The native action works without a Next.js route handler.
Create a form in the dashboard and replace YOUR_FORM_ID with your endpoint ID. No account key belongs in this code.
'use client';
export default function Contact() {
return (
<form action="https://formdrop.wouldairecommend.workers.dev/f/YOUR_FORM_ID" method="POST">
<label htmlFor="email">Email</label>
<input id="email" name="email" type="email" required />
<label htmlFor="message">Message</label>
<textarea id="message" name="message" required />
<input name="_gotcha" tabIndex={-1} autoComplete="off" hidden />
<button type="submit">Send message</button>
</form>
);
}The detail that matters
A server action is an alternative only when you deploy a server runtime; it cannot execute in a static export.
Server action alternative
// app/contact/actions.ts — requires a server runtime
'use server';
export async function sendContact(data: FormData) {
const response = await fetch('https://formdrop.wouldairecommend.workers.dev/f/YOUR_FORM_ID', {
method: 'POST', body: data, headers: { Accept: 'application/json' }
});
if (!response.ok) throw new Error('Could not send message');
}
// In a server component:
// import { sendContact } from './actions';
// <form action={sendContact}>…named fields…</form>After you publish
Send a test from the published page, then check Inbox and Spam. Native forms follow a redirect; fetch clients must request JSON and show errors. Set your allowed domains to the hostnames you actually publish, including any preview hostname you need.
Read the endpoint reference for reserved fields, CORS and redirect rules. Start from the accessible contact template if you need styling.