send.webforms.toRead the docs →

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.

Get an endpointRead the docs

Setup

  1. Copy your endpoint

    Create a form in the dashboard. The endpoint is the only configuration you need.

  2. 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.

  3. 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.

src/lib/ContactForm.svelte
<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.

src/routes/contact/+page.server.js
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

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.

Ready to wire up your Svelte form?

Free for 300 submissions a month. Endpoint in under a minute, no card required.

Start free