Next.js
Use FormFast with Next.js App Router or Pages Router. Works with both client components and server actions.
Client component (App Router)
app/contact/page.tsx
"use client";
import { useState } from "react";
export default function ContactPage() {
const [status, setStatus] = useState<"idle" | "loading" | "success" | "error">("idle");
async function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
e.preventDefault();
setStatus("loading");
const data = Object.fromEntries(new FormData(e.currentTarget));
const res = await fetch("https://formfa.st/f/your_endpoint_id", {
method: "POST",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
body: JSON.stringify(data),
});
setStatus(res.ok ? "success" : "error");
}
if (status === "success") {
return <p>Thanks for reaching out! We'll reply soon.</p>;
}
return (
<form onSubmit={handleSubmit}>
<input type="text" name="name" placeholder="Name" required />
<input type="email" name="email" placeholder="Email" required />
<textarea name="message" placeholder="Message" />
<input type="hidden" name="_gotcha" style={{ display: "none" }} />
<button type="submit" disabled={status === "loading"}>
{status === "loading" ? "Sending..." : "Send"}
</button>
{status === "error" && <p>Something went wrong.</p>}
</form>
);
}Server action
You can also submit to FormFast from a Next.js server action. This keeps your endpoint ID server-side:
app/contact/actions.ts
"use server";
export async function submitContact(formData: FormData) {
const data = Object.fromEntries(formData);
const res = await fetch("https://formfa.st/f/your_endpoint_id", {
method: "POST",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
body: JSON.stringify(data),
});
if (!res.ok) {
throw new Error("Submission failed");
}
return { success: true };
}app/contact/page.tsx
import { submitContact } from "./actions";
export default function ContactPage() {
return (
<form action={submitContact}>
<input type="text" name="name" required />
<input type="email" name="email" required />
<textarea name="message" />
<button type="submit">Send</button>
</form>
);
}Server actions send the request from your server, not the client's browser. This means the IP address logged by FormFast will be your server's IP, not the user's.
Pages Router
The approach is the same as the React guide. Use a client-side form with fetch inside your page component:
pages/contact.tsx
import { useState, FormEvent } from "react";
export default function ContactPage() {
const [sent, setSent] = useState(false);
async function onSubmit(e: FormEvent<HTMLFormElement>) {
e.preventDefault();
const data = Object.fromEntries(new FormData(e.currentTarget));
await fetch("https://formfa.st/f/your_endpoint_id", {
method: "POST",
headers: { "Content-Type": "application/json", Accept: "application/json" },
body: JSON.stringify(data),
});
setSent(true);
}
if (sent) return <p>Thank you!</p>;
return (
<form onSubmit={onSubmit}>
<input type="text" name="name" required />
<input type="email" name="email" required />
<textarea name="message" />
<button type="submit">Send</button>
</form>
);
}