In a React SPA the form is easy; the hard part is where the POST goes. You do not want a Node mailer in the same repo, and a custom API route plus Resend/SendGrid for one contact box is more ops than the feature is worth. This guide shows how to build a React contact form without a backend by posting to a form API with the official @formsreach/react hook.
The same pattern works in Create React App, Vite, and many static exports. For App Router Next.js, use the Next-specific note at the end (still client-side, still no mail server of your own).
What you’ll need
- A React app (Vite or similar)
- Node 18+ for the package install
- A free FormsReach API key from the dashboard
Optional: WhatsApp delivery on Pro or Agency after the form works on email.
The “where do I POST this?” problem
Browser security will not let you SMTP from React. Common workarounds:
- Roll your own API route - you own auth, rate limits, spam, and email provider downtime.
- Serverless function - better, still yours to monitor.
- Form API - browser posts to a managed endpoint with an API key; notifications leave your app.
FormsReach is option 3: spam filtering, monthly credits, free webhooks, and optional WhatsApp on higher plans. Background on channel choice: send form submissions to WhatsApp.
Step 1: Install the React package
npm install @formsreach/react
The package exposes useFormsReach(apiKey), which returns { submit, submitting } suitable for a controlled form onSubmit.
Step 2: Wire the hook to a form
Use real field name attributes. The hook serializes the form and posts to FormsReach for you (including spam-protection fields the SDK manages).
// npm install @formsreach/react
import { useFormsReach } from '@formsreach/react';
function ContactForm() {
const { submit, submitting } = useFormsReach('YOUR_API_KEY');
return (
<form onSubmit={submit}>
<input type="text" name="name" required />
<input type="email" name="email" required />
<textarea name="message" required />
<button type="submit" disabled={submitting}>Submit Form</button>
</form>
);
}
Replace YOUR_API_KEY with your dashboard key. Keep name, email, and message (or your own names) consistent with how you want notifications to look.
Step 3: UX while submitting
submitting is true while the request is in flight. Disable the button (as above) and optionally show “Sending…”. On success, FormsReach can redirect to a thank-you URL you configure, or you can handle success in the product dashboard flow. Prefer one clear success path so users do not double-submit.
Step 4: Validation tips
- Use native
requiredandtype="email"first; they work without extra libraries. - Do not invent CAPTCHA unless you have a fraud problem; FormsReach includes honeypot and server-side filtering.
- Never put secret mail-provider tokens in the client. Only the public form API key belongs in the browser, ideally with domain allowlisting enabled.
Step 5: Notifications (email and optional WhatsApp)
Credits meter usage. Free includes 500 credits/month. A typical path charges 1 credit for an accepted submission and 1 credit for an email notification. Webhooks cost 0 credits and work on every plan.
WhatsApp uses the official Meta WhatsApp Business API on Pro and Agency only. You can ship the React form on Free with email, then enable WhatsApp without rewriting the form.
Static HTML without React is covered here: contact form on a static website without a backend.
Next.js note (App Router)
Use the same package with a Client Component:
// npm install @formsreach/react
'use client';
import { useFormsReach } from '@formsreach/react';
export default function ContactForm() {
const { submit, submitting } = useFormsReach('YOUR_API_KEY');
return (
<form onSubmit={submit}>
<input type="text" name="name" required />
<input type="email" name="email" required />
<textarea name="message" required />
<button type="submit" disabled={submitting}>Submit Form</button>
</form>
);
}
No Route Handler is required for the basic contact form. Keep 'use client' on the file that calls the hook so the browser owns the submit.
Troubleshooting
useFormsReach is not a function / hook error
Confirm @formsreach/react is installed and the import path is exact. Call the hook only inside a function component.
Submit does nothing
Check the Network tab for api.formsreach.com. Inspect status and response body. Bad keys and domain blocks return 4xx.
Works in Vite, fails after static export
Confirm the production bundle still includes the form and that env-based keys are inlined correctly at build time.
Double submissions
Disable the button with submitting and avoid stacking your own fetch on top of submit.
Need zero JS
Use a plain HTML form action instead; see the static site form guide.
Ship the form, skip the mail server
A React contact form without a backend is a solved problem when the POST target is a form API. FormsReach gives you that endpoint, spam filtering, email on Free, free webhooks, and WhatsApp on Pro and Agency through Meta’s Business API, all on a shared monthly credit pool (500 credits on Free).
