We start with some basic SvelteKit Form example snippets, in this post. SvelteKit form issues are one of the topics I get asked for help on most often. So, with the basic example out of the way, we look at 10 pitfalls you should try to avoid in your SvelteKit forms. This should help you debug any issues. If you are still having issues not covered here though, the best piece of advice I can offer is to cut out features until you have things working. Then, once you have the issues fixed, add the features back in one-by‑one.
Let’s start with that base example. We will later add feedback for missing fields, server-side validation using Zod and user experience enhancements.
This minimal code is missing some common user experience and feedback features, but should be enough to get us going!
- basic form using web standards
input fields have corresponding label elements, with
forvalue matching the input
there is no
preventDefault, because we are relying on browser primitives to submit the form
The handler is named
5, because there is no
actionattribute on the
formelement in the Svelte markup. We see how to use named handlers later.
form.getmethod calls (lines
8) match the
nameattribute value on the
textareaelements in the Svelte markup.
Working in TypeScript, form elements are of type
FormDataEntryValue, and we should narrow the type to a more useful
string, ahead of processing (line
console.log()the input email and message values. A typical workflow would involve emailing the message details to a team member who is authorized to handle personally identifiable information (PII). See example code for sending this email using the Postmark REST API below.
- There is no check that the email is valid nor that the visitor left a message. We see how to use Zod for validation further down.
There is no feedback. We redirect the user to the home page, even if the data was not as
expected. We will return a SvelteKit
failobject, below, to provide feedback in the markup.
src/routes/basic-start/+page.server.ts — click to expand code.
Next, we can add some missing features, pointing out trip hazards along the way.
⛔️ No SSG allowed! In your
@sveltejs/adapter-auto(the default) or another SSR compatible adapter, such as
@sveltejs/adapter-netlify. Also, make sure you do not have prerender directives in your server code for form handling routes.
You can build a completely static site with forms in SvelteKit, though you will probably want to use edge functions or serverless functions to handle form submissions. The techniques in this post will not work with prerendered pages.
📮 Most of the time you will want the
POSTform method. As best practice, when there is a side effect (e.g. you log a user in, add a row to the database etc.), use the
POSTmethod on the form element. Use
GETwhen the user just needs to request a document . See MDN HTTP request method docs
🏾🏼 Add an
actionattribute to the form element for named handlers. Above, we used the
defaulthandler in the server action code. You might want to name your handlers, and if you do, you must include an
actionattribute on the form element in the markup. Use this approach to make code intention clearer, or when you have more than one form on a single route.
- Don’t trust users! By all means, use client-side validation, to enhance user experience, but do not rely on it. A savvy user might manipulate the form response, wreaking havoc in your server logic! The Zod library is a common choice for validation, and we see how to integrate it further down. Zod saves you having to work out your own Regex to validate email addresses and such like.
💯 Send the user helpful feedback when their input is invalid. This goes
hand-in-hand with validation, from the previous tip. SvelteKit server actions can return an
failhelper method. This lets you send error messages to the client, as well as track valid inputs (saving the user having to re-enter them).
🤗 Make sure feedback is accessible. We can make use of the new feedback from
the previous tip to let the user know when the inputs were not as expected. You can use
aria-describedbyattributes to keep this feedback accessible.
SvelteKit plumbing makes the
messagevariables returned from the action available on the frontend, via
export let form. See the Grammar check post for an explanation of why there is a double assignment for these identifiers.
Any email field error will be displayed by the template code in lines
31. Notice, we will display the exact message set on the server, saving us re-creating a message. The
smallelement in line
30is important to link the erroneous field, using an
aria-describedbyattribute in line
27. Code for the message input is similar.
🙏🏽 Avoid making the user re-enter details which were perfectly valid. An
exception here is a password. Typically, you will ask the user to re-enter a password when a
form input was rejected. For other fields, though, avoid winding up users; use a
valueattribute to repopulate the fields when a rejected form reloads:
🏋🏽 Let Zod do the heavy lifting. Writing and testing validation code can eat
up a lot of time. Use a validation library like Zod to save your back! There is minimal extra code for this example. Add Zod as a dev dependency
pnpm add -D zod) then, define a schema for the form data:
Here, we specify two fields:
message. By default, with Zod, all fields are required, and you can add
.optional()if the field is accepted, but not necessary.
z.string()details that we expect
required_erroris the error message we want to emit, when the
6) is all we need to ask Zod to check the field value is a valid email. The string passed to
.email()is the error message to emit when the value is not a valid email. Similarly, for
message, we set
As a final step, we want to validate the form entries, on the server, using this new schema:
we validate the form entries in line
if the validation fails, Zod throws an error, which we catch in the block starting at
19, and then return entered values and error messages, using the same format as earlier
We need zero changes in the front end code, as the return value maintains the earlier format.
- we validate the form entries in line
⚾️ Rethrow unhandled errors in SvelteKit handlers. This is possibly the
easiest pitfall to fall into! You might code everything up, test it, see the form submitting
just fine, but then not get the expected redirect to the thank-you page! This comes from the
way SvelteKit manages redirects. Like Remix, it throws redirects. In the Zod code above, we
had to catch an error. The missing line, though, is a rethrow of any errors we did not
handle. Without adding that rethrow, we will catch the redirect in line
18and just swallow it, preventing Svelte from redirecting. An easy fix is to rethrow any errors which we do not handle:
If there is a Zod validation error, the code returns early (from line
22), so the rethow in line
24is not triggered. Importantly, that rethrow will be invoked on the happy path, though!
- 🔐 Help users follow security best practices. For signup and login, consider implementing multifactor authentication (MFA), to help protect users from credential stuffing attacks. Also encourage them to set strong and unique passwords. See more best-practices for SvelteKit login forms.
Improving on the initial version, here, if the
error object which shows which field is awry and what the issue is.
In this post, we saw a concrete SvelteKit form example, as well as 10 mistakes to avoid. More specifically, we saw:
- how to pass form data from the client to the server;
- how to return feedback on invalid fields from the server, repopulating valid fields; and
- debugging a common issue where redirects do not work on SvelteKit server handlers.
Please see the full repo code on the Rodney Lab GitHub repo . The repo includes complete working examples from various stages in the journey above. I do hope you have found this post useful and can use the code in your own SvelteKit project. Let me know if you have any suggestions for improvements. Drop a comment below or reach out on other channels.
- A common cause of redirects inexplicably failing in SvelteKit server code is accidental consumption of SvelteKit thrown objects. SvelteKit uses the throw mechanism (usually used with errors) to handle redirects. Often, you will add a try-catch block in your server handler to manage any exceptions in your own logic. In doing so, it is easy unwittingly to consume SvelteKit thrown objects like redirects. Luckily, this is quick to remedy. Just make sure you rethrow any errors which are not handled by your code. That way, thrown redirects live long enough for SvelteKit to act on them!
- Use default, for your action name, in the server code if you do not provide an action attribute value in the form element markup. However, to make your code easier to follow, you might want to name the handler more descriptively. Let’s say you want to name it `login`. In this case, add an `action` attribute to the form element tag in the markup: `<form … action="?/login">`
If you have found this post useful, see links below for further related content on this site. I do hope you learned one new thing from the video. Let me know if there are any ways I can improve on it. I hope you will use the code or starter in your own projects. Be sure to share your work on Twitter, giving me a mention, so I can see what you did. Finally, be sure to let me know ideas for other short videos you would like to see. Read on to find ways to get in touch, further below. If you have found this post useful, even though you can only afford even a tiny contribution, please consider supporting me through Buy me a Coffee.
Just dropped a new post looking at 10 SvelteKit form errors to avoid.— Rodney (@askRodney) August 7, 2023
Starting with a basic contact form, we add:
- internal email alert with 📮
- validation with Zod,
- user feedback & a11y enhancements.
Hope you find it useful!https://t.co/IYBhVsMd2A
Finally, feel free to share the post on your social media accounts for all your followers who will find it useful. As well as leaving a comment below, you can get in touch via @askRodney on Twitter and also askRodney on Telegram . Also, see further ways to get in touch with Rodney Lab. I post regularly on SvelteKit as well as Search Engine Optimization among other topics. Also, subscribe to the newsletter to keep up-to-date with our latest projects.