DEV Community

Cover image for How to use SvelteKit with Netlify Forms
swyx
swyx

Posted on • Originally published at swyx.io

How to use SvelteKit with Netlify Forms

This is a direct answer to this SvelteKit issue. 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.

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. See demo apps for setup instructions.
  • You can also trigger Netlify functions 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 to indicate interest or i wont do it.

SvelteKit Setup Instructions

Project Init

Go through the standard SvelteKit setup:

npm init svelte@next myapp       
cd myapp
npm i
Enter fullscreen mode Exit fullscreen mode

You can set up GitHub/Netlify either thru CLI or UI - I found some bugs with Netlify CLI when I tried this but it might be fixed by the time you read this:

# 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
Enter fullscreen mode Exit fullscreen mode

or you can just use the UIs for each service

Add SvelteKit Netlify Adapter

npm i -D @sveltejs/adapter-netlify@next       
Enter fullscreen mode Exit fullscreen mode

then add it to svelte.config.cjs:

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: ['*'],
        },
    }
};
Enter fullscreen mode Exit fullscreen mode

then add a netlify.toml file at project root:

[build]
  command = "npm run build"
  publish = "build/"
  functions = "functions/"
Enter fullscreen mode Exit fullscreen mode

You can see these instructions in my netlify adapter docs.

Add the Prerendered Form

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

<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>
Enter fullscreen mode Exit fullscreen mode

Deploy

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

Examples:

Screenshots

image

image

image

image

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:

<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>
Enter fullscreen mode Exit fullscreen mode

Top comments (8)

Collapse
 
inspiredlabs profile image
Inspired Labs - London, United Kingdom • Edited

Please can you link to your preferred method of switching adapters from local to Netlify? (mine is super-clunky, perhaps one using ENV variables).

Also, do you have advice for the version mismatch:

5:32:54 PM: npm ERR! notsup Unsupported engine for @sveltejs/kit@1.0.0-next.142: wanted: {"node":"^12.20 || >=14.13"} (current: {"node":"12.18.0","npm":"6.14.4"})
5:32:54 PM: npm ERR! notsup Not compatible with your version of node/npm: @sveltejs/kit@1.0.0-next.142
5:32:54 PM: npm ERR! notsup Not compatible with your version of node/npm: @sveltejs/kit@1.0.0-next.142
5:32:54 PM: npm ERR! notsup Required: {"node":"^12.20 || >=14.13"}
5:32:54 PM: npm ERR! notsup Actual:   {"npm":"6.14.4","node":"12.18.0"}
Enter fullscreen mode Exit fullscreen mode

I've noticed that when cloning your repo. Thanks for the great tuts so far.

Collapse
 
swyx profile image
swyx

i dont understand what you mean by "switching adapters from local to Netlify". there is no local adapter?

yes for the netlify node version we actually have this in the readme github.com/sveltejs/kit/tree/maste...

Netlify defaults to Node 12.16. SvelteKit requires Node v12.20 to build. You can pin the Node version with a .node-version or .nvmrc file: echo "14" > .nvmrc or set the NODE_ENV environment variable.

Collapse
 
danawoodman profile image
Dana Woodman

Nice writeup! I don't use Netlify Forms but I should def remember to use them more as they're so convenient :)

One minor thing I noticed, you could use on:submit|preventDefault on the AJAX form example

Collapse
 
swyx profile image
swyx

good call, will add

Collapse
 
danawoodman profile image
Dana Woodman

Just noticed something; could you do e.target instead of the getElementById bit?

Thread Thread
 
swyx profile image
swyx

sure but at that point its just JS. i copy and pasted that one haha

Collapse
 
catico profile image
Catico

What are the downsides of prerendering the form vs "leave your "helper form" hidden at build time and render the real form clientside"?

Collapse
 
swyx profile image
swyx

sorry i only just saw this question now. hmm, no real downside, they're basically equivalent as long as you know what you're doing with your SSR skills.