Svelte contact forms
without mail code.
Use a Svelte submit handler or SvelteKit action while Form Plume handles notifications, stored submissions, spam filtering, file uploads, integrations, and signed webhooks.
async function submit(event: SubmitEvent) {
const form = event.currentTarget as HTMLFormElement;
status = "sending";
const response = await fetch(FORM_PLUME_ENDPOINT, {
method: "POST",
headers: { Accept: "application/json" },
body: new FormData(form),
});
status = response.ok ? "sent" : "error";
}The full guide
A lightweight backend for Svelte contact forms.
Choose plain Svelte or a SvelteKit action, keep the form accessible, and avoid custom email infrastructure.
- 1Create your Form Plume accountStart free and give your Svelte 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 SvelteUse a plain Svelte submit handler or SvelteKit form actions, depending on whether the form should post from the browser or through the route. Send one test submission from the real Svelte 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.
Plain Svelte component
For a static Svelte app, submit directly to Form Plume from the browser.
<script lang="ts">
const FORM_PLUME_ENDPOINT = "PASTE_YOUR_FORM_PLUME_ENDPOINT_HERE";
let status: "idle" | "sending" | "sent" | "error" = "idle";
async function submit(event: SubmitEvent) {
const form = event.currentTarget as HTMLFormElement;
status = "sending";
const response = await fetch(FORM_PLUME_ENDPOINT, {
method: "POST",
headers: { Accept: "application/json" },
body: new FormData(form),
});
if (response.ok) {
form.reset();
status = "sent";
} else {
status = "error";
}
}
</script>
<form on:submit|preventDefault={submit}>
<label for="email">Email</label>
<input id="email" type="email" name="email" autocomplete="email" required>
<label for="message">Message</label>
<textarea id="message" name="message" rows="5" required />
<button disabled={status === "sending"}>
{status === "sending" ? "Sending..." : "Send message"}
</button>
{#if status === "sent"}
<p role="status">Thanks, we got your message.</p>
{:else if status === "error"}
<p role="alert">Please try again.</p>
{/if}
</form>SvelteKit action
If you want the route to own validation and redirects, forward the form from a SvelteKit action.
// src/routes/contact/+page.server.ts
import { redirect, type Actions } from "@sveltejs/kit";
const FORM_PLUME_ENDPOINT = "PASTE_YOUR_FORM_PLUME_ENDPOINT_HERE";
export const actions: Actions = {
default: async ({ request }) => {
const formData = await request.formData();
const response = await fetch(FORM_PLUME_ENDPOINT, {
method: "POST",
body: formData,
});
if (!response.ok) {
return { ok: false };
}
throw redirect(303, "/thanks");
},
};<!-- src/routes/contact/+page.svelte -->
<form method="POST">
<input name="email" type="email" required>
<textarea name="message" required />
<button>Send message</button>
</form>Enhanced SvelteKit forms
Use SvelteKit's enhance helper when you want progressive enhancement while keeping the action as the source of truth. The unenhanced form still works.
A SvelteKit action is useful for redirects and validation, but it should not become a custom mail backend. Form Plume handles notifications, storage, spam filtering, uploads, integrations, and webhooks.
Uploads and field names
Use FormData for files and do not set multipart headers manually.
Keep fields named name, email, message, company, phone, or attachment where possible. Those names make dashboard review and downstream integrations easier.
Svelte-specific checks
Reset the form only after a successful response.
Keep success and error messages in the markup so assistive technology can announce them.
Avoid duplicating the submission into analytics or automation calls from the browser. Let Form Plume fan accepted submissions out after spam filtering.
Primary sources
FAQ
Svelte form questions
before ship.
One line. Zero backend.
