Frameworks and libraries
Add a contact form to a Svelte app
Svelte's form story is unusually good - SvelteKit actions with `use:enhance` give you progressive enhancement almost for free. What it does not give you is somewhere for the data to go. WebForms is that somewhere. Below: a plain Svelte component using runes, and a SvelteKit action that forwards the submission server-side.
Setup
Copy your endpoint
Create a form in the dashboard. The endpoint is the only configuration you need.
Pick client or server
Plain Svelte posts from the browser. SvelteKit can post from a form action instead if you prefer everything to go through your server.
Add destinations
Email, Slack, Discord, Telegram, webhooks - configured in the dashboard, changed without a redeploy.
Svelte examples
Swap in your own endpoint and these run as-is.
Svelte 5 runes, posting from the browser.
<script>
let status = $state("idle");
let error = $state(null);
async function onSubmit(e) {
status = "sending";
const res = await fetch("https://send.webforms.to/wft_your_key", {
method: "POST",
headers: { accept: "application/json" },
body: new FormData(e.currentTarget),
});
const data = await res.json();
if (data.ok) {
status = "sent";
} else {
error = data.message;
status = "error";
}
}
</script>
{#if status === "sent"}
<p role="status">Thanks, we got it.</p>
{:else}
<form onsubmit={(e) => { e.preventDefault(); onSubmit(e); }}>
<input name="name" required />
<input name="email" type="email" required />
<textarea name="message" required></textarea>
<button disabled={status === "sending"}>Send</button>
{#if error}<p role="alert">{error}</p>{/if}
</form>
{/if}SvelteKit form action. Pair it with use:enhance for progressive enhancement.
import { fail, redirect } from "@sveltejs/kit";
export const actions = {
default: async ({ request }) => {
const formData = await request.formData();
const res = await fetch("https://send.webforms.to/wft_your_key", {
method: "POST",
headers: { accept: "application/json" },
body: formData,
});
const data = await res.json();
if (!data.ok) {
return fail(400, { message: data.message ?? "Submission failed" });
}
redirect(303, "/contact/thanks");
},
};Worth knowing
- With a SvelteKit action the POST comes from your server, so the visitor's IP is not seen by our spam checks. Post from the browser if you want that signal.
Svelte form FAQ
Both work. A form action gives you progressive enhancement and keeps the endpoint off the client; a browser fetch preserves per-visitor spam signals like IP and fill time.
Yes. With adapter-static there is no server to run actions, so use the client-side example or a plain form POST with a _next redirect.
Related guides
Ready to wire up your Svelte form?
Free for 300 submissions a month. Endpoint in under a minute, no card required.
Start free