FormThunder isn't open yet. This site describes the service as it will run at launch. Find out more

FormThunder
Menu

Add a Svelte contact form with runes and no server endpoint

A Svelte 5 contact form needs a state rune for its status and a submit handler that posts to FormThunder, with no SvelteKit endpoint or form action. FormThunder stores each submission and emails your verified address. Because the form keeps its action URL, it still works as a plain post when JavaScript hasn't loaded yet.

Updated

The Svelte code

ContactForm.svelte
<script>
  let status = $state("idle");

  async function submit(event) {
    event.preventDefault();
    const form = event.currentTarget;
    status = "sending";
    try {
      const response = await fetch(form.action, {
        method: "POST",
        headers: { "Content-Type": "application/json", Accept: "application/json" },
        body: JSON.stringify(Object.fromEntries(new FormData(form))),
      });
      const data = await response.json();
      status = data.success ? "sent" : "error";
      if (data.success) form.reset();
    } catch {
      status = "error";
    }
  }
</script>

<form action="https://formthunder.com/submit" method="POST" onsubmit={submit}>
  <input type="hidden" name="access_key" value="YOUR_ACCESS_KEY" />
  <input type="checkbox" name="botcheck" style="display: none" tabindex="-1" />
  <label>Name <input name="name" required /></label>
  <label>Email <input name="email" type="email" required /></label>
  <label>Message <textarea name="message" required></textarea></label>
  <button disabled={status === "sending"}>Send</button>
  {#if status === "sent"}<p role="status">Thanks, we got your message.</p>{/if}
  {#if status === "error"}<p role="alert">That didn't send. Please try again.</p>{/if}
</form>

Replace YOUR_ACCESS_KEY with your free key. It's public by design, so it's safe in client code.

Notes for Svelte

  • In Svelte 4, replace $state("idle") with let status = "idle" and onsubmit={submit} with on:submit|preventDefault={submit}.
  • Don't use SvelteKit's use:enhance here. It's for your own form actions, and this form posts to another origin.
  • In SvelteKit, read a key from $env/static/public with a PUBLIC_ prefix, such as PUBLIC_FORMTHUNDER_KEY.

Or have your AI add it

Connect the MCP server, then ask. The agent creates the form and writes the code for you, and it can send a real test when it's done.

You, to your AI
Add a FormThunder contact form to this Svelte site that emails hello@example.com. Send a test when you're done.

Questions

Does this need adapter-node or a server?

No. It works with adapter-static, because all the sending happens in the browser or through a plain form post.

Will this form work before hydration?

Yes. Until the script loads it posts normally, then the visitor sees the success page or your redirect.

Get your Svelte form sending

The free plan covers 250 submissions a month, with MCP, the CLI and the brand kit included.