How to use SvelteKit with Netlify Forms
Tags: tutorial, svelte, netlify
Published: 2021-04-25 22:28:24

---
title: How to use SvelteKit with Netlify Forms
published: true
description: a simple tutorial
tags: Tutorial, Svelte, Netlify
slug: sveltekit-netlify-forms
cover_image: https://user-images.githubusercontent.com/6764957/116011560-3dda9480-a658-11eb-8954-fd8cf7160ae2.png
canonical_url: https://www.swyx.io/sveltekit-netlify-forms
---

This is a direct answer to [this SvelteKit issue](https://github.com/sveltejs/kit/issues/942). I see a lot of JS developers struggle with using Netlify Forms, so I want to help.

## 9 Min Video Walkthru

This is the video version of the instructions below.

{% youtube cj3f2Xth5Mk %}

## Context

Netlify Forms were designed primarily for traditional static site generators like Hugo and Jekyll, using HTML crawling to initialize forms. The idea is like this:

- Your static site is a folder of `.html` files
- Netlify crawls all of them looking for `<form netlify>` tags (or `<form data-netlify="true">`, because some projects like Create React App or Gatsby helpfully delete unrecognized attributes for you, what fun)
- For each detected tag, it sets up a dedicated "form" which is pretty much an append-only schemaless document store of all submissions.
- These are received via a special endpoint set up at the domain root (`/`) looking for `POST` requests with `"Content-Type": "application/x-www-form-urlencoded"` (or with `multipart` for file uploads)
- **Crucially: If no forms are detected, this feature doesn't work**.

Many JS framework users struggle to use them because:

- the form needs to exist in HTML at build time but JS frameworks render them at runtime. 
- SvelteKit introduces another wrinkle in that you have to decide whether to prerender the form. 
- JS framework users also often want to use AJAX to offer a better UX. So again you have to do things slightly differently than with pure HTML forms. 

### Optional Features You May Want

What I cover here is just the simplest solution to help people solve the immediate pain point. You can also:

- leave your "helper form" hidden at build time and render the real form clientside
- upload files with Netlify Forms (underrated)
- do progressive enhancement of behavior from HTML to JS. 
- For spam prevention, there is support for [honeypot and recaptcha](https://docs.netlify.com/forms/spam-filters/). See [demo apps](https://github.com/sw-yx/gatsby-netlify-form-example-v2) for setup instructions.
- You can also [trigger Netlify functions](https://docs.netlify.com/functions/trigger-on-events/) on successful submissions to do arbitrary logic (like notify you on Slack or create an account)

I'll come back and add that to this blogpost if I ever get the time. Pls [yell at me](https://twitter.com/swyx/status/1386447885936390147) to indicate interest or i wont do it.

## SvelteKit Setup Instructions

### Project Init

Go through the standard SvelteKit setup:

```bash
npm init svelte@next myapp       
cd myapp
npm i
```

You can set up GitHub/Netlify either thru CLI or UI - I found some [bugs](https://github.com/netlify/cli/issues/2229) with Netlify CLI when I tried this but it might be fixed by the time you read this:

```bash
# optional: set up git/github/netlify deploy via CLI
git init && git add . && git commit -m "hi"
gh repo create # have the github cli installed
ntl init # netlify cli
```

or you can just use the UIs for each service

### Add SvelteKit Netlify Adapter

```bash
npm i -D @sveltejs/adapter-netlify@next       
```

then add it to `svelte.config.cjs`:

```js
const adapter = require('@sveltejs/adapter-netlify');
module.exports = {
	kit: {
		adapter: adapter(), // currently the adapter does not take any options
		target: '#svelte',
		prerender: {
			crawl: true,
			enabled: true,
			force: true,
			pages: ['*'],
		},
	}
};
```

then add a `netlify.toml` file at project root:

```
[build]
  command = "npm run build"
  publish = "build/"
  functions = "functions/"
```

You can see these instructions in [my netlify adapter docs](https://github.com/sveltejs/kit/pull/1217).

### Add the Prerendered Form

Head to `/src/routes/index.svelte` and add the form accordingly.

```html
<script context="module">
	export const prerender = true;
</script>


<h1>Welcome to SvelteKit</h1>
<p>Visit <a href="https://kit.svelte.dev">kit.svelte.dev</a> to read the documentation</p>

<form name="test" method="post" netlify netlify-honeypot="bot-field">
    <input type="hidden" name="form-name" value="test" />
    <input type="text" name="bot-field" />
    <p>
        <label>Your Name: <input type="text" name="name" /></label>
    </p>
    <p>
        <label>Your Email: <input type="email" name="email" /></label>
    </p>
    <p>
        <label>Message: <textarea name="message" /></label>
    </p>
    <p>
        <button type="submit">Send</button>
    </p>
</form>
```

### Deploy

Now you should be able to push to GitHub and have it build and render the form successfully.

Examples:

- https://github.com/sw-yx/sveltekitnetlifyforms
- https://sveltekitnetlifyforms.netlify.app/

## Screenshots

![image](https://user-images.githubusercontent.com/6764957/116011598-83975d00-a658-11eb-8f1e-9140698fd22c.png)


![image](https://user-images.githubusercontent.com/6764957/116011546-27343d80-a658-11eb-9a3e-862cbe61ea08.png)


![image](https://user-images.githubusercontent.com/6764957/116011560-3dda9480-a658-11eb-8954-fd8cf7160ae2.png)


![image](https://user-images.githubusercontent.com/6764957/116011573-564aaf00-a658-11eb-8f94-56c5ec824014.png)


## Graveyard: AJAX Example

> Warning: this is untested code - I ran out of time but dumping it here anyway in case it helps someone

If you want an AJAX experience for your form here is some untested code I was working on that may help you get going:

```html
<script context="module">
  export const prerender = true;
</script>

<script>
  let isSubmitting = false;

  const handleSubmit = (e) => {
    let myForm = document.getElementById("test");
    let formData = new FormData(myForm);
    isSubmitting = true;
    return fetch("/", {
      method: "POST",
      headers: { "Content-Type": "application/x-www-form-urlencoded" },
      body: new URLSearchParams(formData).toString(),
    })
      .then(() => {
        console.log("Form successfully submitted");
        isSubmitting = false;
        myForm.reset();
      })
      .catch((error) => {
        alert(error);
        isSubmitting = false;
      });
  };
</script>

<h1>Welcome to SvelteKit</h1>
<p>
  Visit <a href="https://kit.svelte.dev">kit.svelte.dev</a> to read the documentation
</p>

<form
  id="test"
  name="test"
  on:submit|preventDefault={handleSubmit}
  netlify
  netlify-honeypot="bot-field"
>
  <input type="hidden" name="form-name" value="test" />
  <input type="text" name="bot-field" style="opacity: 0" />
  <p>
    <label>Your Name: <input type="text" name="name" /></label>
  </p>
  <p>
    <label>Your Email: <input type="email" name="email" /></label>
  </p>
  <p>
    <label>Message: <textarea name="message" /></label>
  </p>
  <p>
    {#if isSubmitting}
      <div>Submitting</div>
    {:else}
      <button type="submit">Send</button>
    {/if}
  </p>
</form>
```