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 forPOST
requests with"Content-Type": "application/x-www-form-urlencoded"
(or withmultipart
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
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
or you can just use the UIs for each service
Add SvelteKit Netlify Adapter
npm i -D @sveltejs/adapter-netlify@next
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: ['*'],
},
}
};
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.
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>
Deploy
Now you should be able to push to GitHub and have it build and render the form successfully.
Examples:
Screenshots
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>
Top comments (8)
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:
I've noticed that when cloning your repo. Thanks for the great tuts so far.
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...
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 examplegood call, will add
Just noticed something; could you do
e.target
instead of thegetElementById
bit?sure but at that point its just JS. i copy and pasted that one haha
What are the downsides of prerendering the form vs "leave your "helper form" hidden at build time and render the real form clientside"?
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.