Remix contact forms
with route actions.
Let your action validate, redirect, and stay progressive while Form Plume handles email notifications, stored submissions, spam filtering, uploads, integrations, and webhooks.
export async function action({ request }) {
const formData = await request.formData();
const response = await fetch(FORM_PLUME_ENDPOINT, {
method: "POST",
body: formData,
});
if (!response.ok) {
return { error: "Please try again." };
}
return redirect("/thanks");
}The full guide
A route-action backend for Remix contact forms.
Use Remix actions for the web flow, then let Form Plume own delivery, storage, spam filtering, and downstream workflows.
- 1Create your Form Plume accountStart free and give your Remix form a hosted endpoint for email, submissions, spam filtering, uploads, integrations, and webhooks.Start free
- 2Create the form and copy the endpointCopy the endpoint URL from Form Plume. It looks like
https://api.formplume.com/f/your-slug - 3Connect it inside RemixUse a Remix route action to receive FormData, forward it to Form Plume, and redirect after success. Send one test submission from the real Remix app or preview environment and confirm it reaches Form Plume.
You can use this AI prompt to hand the platform-specific wiring to an assistant without accidentally creating a backend.
Remix route action pattern
Remix actions are a natural fit for contact forms. The browser posts to the route, the action forwards FormData to Form Plume, and the same route controls the redirect or error.
import {
Form,
redirect,
useActionData,
useNavigation,
type ActionFunctionArgs,
} from "react-router";
const FORM_PLUME_ENDPOINT = "PASTE_YOUR_FORM_PLUME_ENDPOINT_HERE";
export async function action({ request }: ActionFunctionArgs) {
const formData = await request.formData();
const response = await fetch(FORM_PLUME_ENDPOINT, {
method: "POST",
body: formData,
});
if (!response.ok) {
return { error: "We could not send your message. Please try again." };
}
return redirect("/thanks");
}
export default function ContactRoute() {
const actionData = useActionData<typeof action>();
const navigation = useNavigation();
const sending = navigation.state === "submitting";
return (
<Form method="post">
<label htmlFor="name">Name</label>
<input id="name" name="name" autoComplete="name" required />
<label htmlFor="email">Email</label>
<input id="email" type="email" name="email" autoComplete="email" required />
<label htmlFor="message">Message</label>
<textarea id="message" name="message" rows={5} required />
<button type="submit" disabled={sending}>
{sending ? "Sending..." : "Send message"}
</button>
{actionData?.error && <p role="alert">{actionData.error}</p>}
</Form>
);
}Form Plume handles email notifications, submission storage, spam filtering, file uploads, integrations, and webhooks after the action forwards the request.
Progressive enhancement is built in
The route action works before JavaScript hydrates. After hydration, Remix gives you pending state through useNavigation.
This keeps the form resilient while still feeling app-like.
Uploads
File uploads work because the action reads request.formData().
<Form method="post" encType="multipart/form-data">
<input type="file" name="attachment" accept=".pdf,.png,.jpg" />
<button type="submit">Send message</button>
</Form>Forward the same FormData to Form Plume. Do not convert it to JSON.
Validation strategy
Use route actions for required server-side checks that cannot be trusted to the browser. Return field errors from the action when the visitor should fix something.
Keep Form Plume as the delivery backend. The action can validate and redirect, but it should not grow into an SMTP client or submissions database.
Keep the Remix action focused on validation and forwarding. Form Plume should stay responsible for delivery, storage, spam checks, and integrations.
Workflow after submit
Once Form Plume accepts the forwarded submission, it can notify email, store the message, quarantine suspicious spam, and trigger Slack, Discord, Google Sheets, Mailchimp, ActiveCampaign, or a signed webhook.
Primary sources
FAQ
Remix form questions
before launch.
One line. Zero backend.
