← All guides

Add form notifications to a Svelte app

This guide shows you how to create a contact form in Svelte 5 (or SvelteKit) that sends submissions to your email via Form Alert.

Prerequisites

Contact form component

Create a new file ContactForm.svelte and add the following. Replace YOUR_ACCESS_KEY with your actual access key.

ContactForm.svelte
<script lang="ts">
  let status = $state<
    "idle" | "sending" | "sent" | "error"
  >("idle");

  async function handleSubmit(
    e: SubmitEvent & { currentTarget: HTMLFormElement }
  ) {
    e.preventDefault();
    status = "sending";

    const formData = new FormData(e.currentTarget);
    const data = Object.fromEntries(formData);

    try {
      const res = await fetch(
        "https://api.form-alert.com/v1/submit",
        {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
          },
          body: JSON.stringify(data),
        }
      );

      if (res.ok) {
        status = "sent";
        e.currentTarget.reset();
      } else {
        status = "error";
      }
    } catch {
      status = "error";
    }
  }
</script>

<form onsubmit={handleSubmit}>
  <input
    type="hidden"
    name="access_key"
    value="YOUR_ACCESS_KEY"
  />

  <label for="name">Name</label>
  <input type="text" name="name" id="name" required />

  <label for="email">Email</label>
  <input type="email" name="email" id="email" required />

  <label for="message">Message</label>
  <textarea name="message" id="message" required></textarea>

  <button type="submit" disabled={status === "sending"}>
    {status === "sending" ? "Sending..." : "Send message"}
  </button>

  {#if status === "sent"}
    <p>Message sent!</p>
  {/if}
  {#if status === "error"}
    <p>Something went wrong. Try again.</p>
  {/if}
</form>

Usage

Import and use the component in any page or layout.

<script>
  import ContactForm from "./ContactForm.svelte";
</script>

<h1>Contact us</h1>
<ContactForm />

SvelteKit: keeping the key server-side (optional)

In SvelteKit, you can proxy through a server endpoint to keep your access key out of client-side code.

src/routes/api/contact/+server.ts
// src/routes/api/contact/+server.ts
import { json, error } from "@sveltejs/kit";
import { FORM_ALERT_KEY } from "$env/static/private";

export async function POST({ request }) {
  const body = await request.json();

  const res = await fetch(
    "https://api.form-alert.com/v1/submit",
    {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        ...body,
        access_key: FORM_ALERT_KEY,
      }),
    }
  );

  if (!res.ok) {
    error(500, "Failed to send");
  }

  return json({ ok: true });
}

Then update the form to POST to /api/contact instead.

Next steps