Beginner5 minUpdated Mar 27, 2026

How to Add a Contact Form to SvelteKit

Add a working contact form to your SvelteKit app with bind:value and fetch. No SvelteKit form actions or server endpoints needed.

Prerequisites

  • A SvelteKit project
  • A FormsList account (free)
  • Basic knowledge of Svelte

TL;DR

To add a contact form to SvelteKit, create a Svelte component with bind:value and submit via fetch to `https://formslist.com/f/your-form-id`. No SvelteKit form actions or server endpoints needed.

1

Create a FormsList form endpoint

Sign up for a free FormsList account and create a new form. Copy the unique endpoint URL — you will use it as the fetch URL in your Svelte component.

// Your endpoint will look like this:
// https://formslist.com/f/YOUR_FORM_HASH
2

Build the Svelte contact form component

Create a new component using Svelte 5's $state rune for reactive form fields. The handleSubmit function collects form data and posts it to your FormsList endpoint.

<script lang="ts">
  let name = $state('')
  let email = $state('')
  let message = $state('')
  let status = $state<'idle' | 'sending' | 'sent' | 'error'>('idle')

  async function handleSubmit(e: SubmitEvent) {
    e.preventDefault()
    status = 'sending'

    const formData = new FormData()
    formData.append('name', name)
    formData.append('email', email)
    formData.append('message', message)

    try {
      const res = await fetch('https://formslist.com/f/YOUR_FORM_HASH', {
        method: 'POST',
        body: formData,
      })

      if (res.ok) {
        status = 'sent'
        name = ''
        email = ''
        message = ''
      } else {
        status = 'error'
      }
    } catch {
      status = 'error'
    }
  }
</script>

<form onsubmit={handleSubmit} class="space-y-4 max-w-md">
  <div>
    <label for="name" class="block text-sm font-medium">Name</label>
    <input
      id="name"
      bind:value={name}
      type="text"
      required
      class="mt-1 block w-full rounded border p-2"
    />
  </div>
  <div>
    <label for="email" class="block text-sm font-medium">Email</label>
    <input
      id="email"
      bind:value={email}
      type="email"
      required
      class="mt-1 block w-full rounded border p-2"
    />
  </div>
  <div>
    <label for="message" class="block text-sm font-medium">Message</label>
    <textarea
      id="message"
      bind:value={message}
      rows="4"
      required
      class="mt-1 block w-full rounded border p-2"
    />
  </div>
  <button
    type="submit"
    disabled={status === 'sending'}
    class="rounded bg-blue-600 px-4 py-2 text-white hover:bg-blue-700 disabled:opacity-50"
  >
    {status === 'sending' ? 'Sending...' : 'Send Message'}
  </button>
  {#if status === 'sent'}
    <p class="text-green-600">Message sent successfully!</p>
  {/if}
  {#if status === 'error'}
    <p class="text-red-600">Something went wrong. Please try again.</p>
  {/if}
</form>
3

Add the component to a SvelteKit page

Import your ContactForm component into a SvelteKit page route. Create a +page.svelte file in your routes directory.

<!-- src/routes/contact/+page.svelte -->
<script>
  import ContactForm from '$lib/components/ContactForm.svelte'
</script>

<main class="mx-auto max-w-2xl py-12 px-4">
  <h1 class="text-3xl font-bold mb-6">Contact Us</h1>
  <p class="mb-8 text-gray-600">
    Fill out the form below and we will get back to you within 24 hours.
  </p>
  <ContactForm />
</main>
4

Test and configure notifications

Submit a test message and check your FormsList dashboard. Enable email notifications, auto-responders, or connect Slack and Google Sheets integrations from the dashboard.

Frequently Asked Questions

Ready to collect form submissions?

Set up your form backend in under a minute. No server required, no complex configuration — just a simple endpoint for your forms.