-
-
Notifications
You must be signed in to change notification settings - Fork 73
Multiple forms on the same page are possible by setting options.id
for each form (one can have the default id, undefined
). This prevents them from interfering with with each other, which can happen since they all update the same $page.status
and $page.form
.
export const actions = {
default: async (event) => {
const loginForm = await superValidate(event, schema, { id: 'login-form' });
return { loginForm }
}
} satisfies Actions;
Please note that this is a server-to-client communication, so posting to a form action or endpoint won't make the server automatically aware that a specific form was sent! In the example above, the update will be applied to login-form
on the client, no matter who posted to it.
If you want to communicate to the server which form id was sent, it could be as simple as using different form actions, or in a more dynamic fashion, using a hidden form field or a GET variable, to set the id
used when calling superValidate
. You could also set it afterwards, before returning it to the client, it doesn't matter.
On the client, if you don't send any data to the form initially, you can set the id
directly in the first argument to superForm
:
const { form, errors } = superForm('login-form', schema);
// If data is used, the id is sent along with it.
const { form, errors } = superForm(data.loginForm, schema);
// In advanced cases, you can set the id as an option.
const { form, errors } = superForm(data.anotherForm, schema, { id: 'special-id' });
See this wiki entry for a list of default values, used when data for a schema field is missing.
Yes, you can set a default
schema value to anything you'd like it to be. For example with the classic "agree to terms" checkbox:
const schema = z.object({
age: z.number().positive().default(NaN),
agree: z.literal(true).default(false as true)
})
This looks strange, but will ensure that an age must be selected and the agree checkbox is unchecked as default, and will only accept true as a value. Just note that you will bypass the type system with this, so the default value will not correspond to the data type, but this will usually not be a problem since form.valid
will be false
if the default values are posted as-is, and that should be the main determinant whether the data is trustworthy.
When you start to configure the library to suit your stack, it's recommended to create an object with default options that you will refer to instead:
import { superForm } from 'sveltekit-superforms/client';
import type { AnyZodObject } from 'zod';
export function yourSuperForm<T extends AnyZodObject>(
...params: Parameters<typeof superForm<T>>
) {
return superForm(params[0], {
// Your defaults here
errorSelector: '.has-error',
delayMs: 300,
...params[1]
});
}
Currently, file uploads are not handled with sveltekit-superforms
. The recommended way to do it is to grab the FormData
and extract the files from there, after validation:
export const actions = {
default: async ({ request }) => {
const formData = await request.formData();
const form = await superValidate(formData, schema);
if (!form.valid) return fail(400, { form });
const file = formData.get('file');
if (file instanceof File) {
// Do something with the file.
}
return { form };
}
} satisfies Actions;
Update: In version 0.6.0+, this will be possible!
Making message a generic type will complicate the API and its types, and won't work with redirects anyway, so I have three suggestions if you need more than a string
:
- If you just want it to work with the
message
property, combine it with$page.status
to determine whether there's an error or not. - Use sveltekit-flash-message for a complete solution that works with redirects. It can be directly integrated into superforms, documented here.
- Add an optional
message
field to the schema, then set its value before returning from the form action.
When applyAction is false, the form won't update $page.data
and $page.status
, so you need to handle page updates yourself for that form, as described in SvelteKit's use:enhance docs.
Note that options.invalidateAll
is true
as default, so if you want to make a form completely self-contained, neither touching $page
nor running any load
functions on success
, set it to false
as well.
Yes, there is a helper function for constructing an ActionResult
that can be returned from endpoints. See its API reference for more information!