Add a working contact form to your SvelteKit app with bind:value and fetch. No SvelteKit form actions or server endpoints needed.
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.
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_HASHCreate 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>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>Submit a test message and check your FormsList dashboard. Enable email notifications, auto-responders, or connect Slack and Google Sheets integrations from the dashboard.
No. Since FormsList handles the backend, you can skip SvelteKit form actions and +page.server.ts files entirely. A simple client-side fetch is all you need.
Yes. Replace the $state rune with regular let declarations; Svelte 4 makes top-level let variables reactive automatically. The rest of the code works the same.
Yes. Since the form submits to an external FormsList endpoint, it works perfectly with adapter-static. No server-side rendering or API routes are needed.
200 free submissions a month and a live endpoint in 30 seconds. No server, no credit card, just point your form at it.