Submit from a client component directly to SmartFormify. Keep the route handler optional and manage loading, errors, redirects, and confirmation inside the form UI.
Choose the request location
Client component
DIRECT
Shortest setup. The browser sends the request and updates the form state.
Route handler or Server Action
Optional when the application already needs server-side validation or processing.
App Router setup
The component reads the JSON returned by SmartFormify and uses it for success, errors, redirects, and thank-you content. The environment tab keeps endpoint URLs separate across deployments.
App Router client component
jsx
The client component sends the request and handles the JSON response returned by SmartFormify.
"use client";
import { useState } from "react";
const ENDPOINT_URL = process.env.NEXT_PUBLIC_SMARTFORMIFY_ENDPOINT;
export default function ContactForm() {
const [state, setState] = useState({ status: "idle", message: "" });
async function handleSubmit(event) {
event.preventDefault();
const form = event.currentTarget;
if (!form.reportValidity()) return;
setState({ status: "loading", message: "" });
const data = Object.fromEntries(new FormData(form).entries());
try {
const response = await fetch(ENDPOINT_URL, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ data })
});
const result = await response.json();
if (!response.ok || !result.success) {
throw new Error(result.message || "Submission failed.");
}
if (result.data.redirect_url) {
window.location.assign(result.data.redirect_url);
return;
}
setState({
status: "success",
message: result.data.thank_you_content
});
form.reset();
} catch (error) {
setState({ status: "error", message: error.message });
}
}
return (
<form onSubmit={handleSubmit}>
<input type="email" name="email" required />
<textarea name="message" required />
<button disabled={state.status === "loading"}>
{state.status === "loading" ? "Sending..." : "Send"}
</button>
{state.message && (
<div
role={state.status === "error" ? "alert" : "status"}
dangerouslySetInnerHTML={{ __html: state.message }}
/>
)}
</form>
);
}STEP 01
Add use client, form state, and the submit handler.
STEP 02
Set the endpoint URL for local, preview, and production builds.
STEP 03
Allow only deployments that submit directly from the browser.
Deployment checks
A preview domain needs access only when the preview form sends directly to the endpoint.