API reference
Throughout the reference, the following types are represented:
/**
* T represents a validation schema.
*
* z.object({
* name: z.string().min(2)
* })
*/
T extends AnyZodObject
/**
* S refers to the underlying type of the schema,
* the actual data structure.
*
* { name: string }
*/
S = z.infer<T>
/**
* Nested represents a structure where the values in S
* are replaced with the second parameter.
*
* { name: string[] | undefined }
*/
Nested<S, string[] | undefined> // Errors for each field in S
Server API
import {
superValidate,
setError,
message,
actionResult
} from 'sveltekit-superforms/server';
superValidate(schema | data, schema? | options?, options?)
If you want the form to be initially empty, you can pass the schema as the first parameter:
superValidate<T, M = any>(
schema: T,
options?: SuperValidateOptions
): Promise<Validation<T, M>>
If you want to populate the form, for example from a database or URL
parameters in the load function, or FormData
in the form actions, send the data as the first parameter, the schema second:
superValidate<T, M = any>(
data:
| RequestEvent
| Request
| FormData
| URL
| URLSearchParams
| Partial<S>
| null
| undefined,
schema: T,
options?: SuperValidateOptions
): Promise<Validation<T, M>>
Options:
SuperValidateOptions = {
id?: string // Form id, for multiple forms support
errors?: boolean // Add or remove errors from output (preserves valid status)
includeMeta = false; // Add metadata to the validation object
}
See this page for information about id
and multiple forms on the same page.
Error and data behavior
- If the data passed to
superValidate
is not empty, errors will be returned unless theerrors
option isfalse
. - Vice versa, if the data is empty, no errors will be returned unless
errors
istrue
.
This does not affect the valid
property of the Validation
object, which always indicates whether validation succeeded or not.
Return value from superValidate
Validation<T, M = any> = {
valid: boolean;
empty: boolean;
data: S;
errors: Nested<S, string[] | undefined>;
constraints: Nested<S, InputConstraints | undefined>;
message?: M;
id?: string;
meta?: { types: Nested<S, string> }
};
If data is empty, a Validation
object with default values for the schema is returned, in this shape:
{
valid: false;
empty: true;
errors: options.errors ? Nested<S, string[] | undefined> : {};
data: S;
constraints: Nested<S, InputConstraints>;
id?: undefined;
message?: undefined;
meta?: { types: Record<keyof S, string> }
}
See this page for a list of default schema values.
Input constraints
/**
* HTML input constraints returned from superValidate
* Properties are mapped from the schema:
*/
InputConstraints = Partial<{
required: boolean; // Not nullable(), nullish() or optional()
pattern: string; // z.string().regex(r)
min: number | string; // number if z.number.min(n), ISO date string if z.date().min(d)
max: number | string; // number if z.number.max(n), ISO date string if z.date().max(d)
step: number; // z.number().step(n)
minlength: number; // z.string().min(n)
maxlength: number; // z.string().max(n)
}>;
setError(form, field, error, options?)
setError(
form: Validation<T, M>,
field: keyof S | [keyof S, ...(string | number)[]] | [] | null,
error: string | string[],
options?: { overwrite = false, status = 400 }
) : ActionFailure<{form: Validation<T, M>}>
For setting errors on the form after validation. It returns a fail(status, { form })
so it can be returned immediately, or more errors can be added by calling it multiple times before returning.
Use the overwrite
option to remove all previously set errors for the field, and status
to set a different status than the default 400
.
If the field
argument is set to an empty array or null
, the error will be a form-level error that can be accessed on the client with $errors._errors
.
message(form, message, options?)
message(
form: Validation<T, M>,
message: M,
options?: { status? : number }
) : { form: Validation<T, M> } | ActionFailure<{form: Validation<T, M>}>
message
is a convenience method for setting form.message
, best explained by an example:
import { message, superValidate } from 'sveltekit-superforms/server';
export const actions = {
default: async (event) => {
const form = await superValidate<typeof schema, string>(event, schema);
if (!form.valid) {
// Will return fail(400, { form }) since form isn't valid
return message(form, 'Invalid form');
}
if (form.data.email.includes('spam')) {
// Will also return fail, since status is >= 400
return message(form, 'No spam please', {
status: 403
});
}
// Returns { form }
return message(form, 'Valid form!');
}
};
actionResult(type, data?, options? | status?)
When using endpoints instead of form actions, you must return an ActionResult
, throw redirect(...)
won’t work for example, superForm
expects an ActionResult
.
This method helps you construct one in a Response
object, so you can return a validation object from your API/endpoints.
actionResult('success', { form }, (status = 200));
actionResult('failure', { form }, (status = 400));
actionResult('redirect', '/', (status = 303));
actionResult('error', 'Error message', (status = 500));
Additionally, the redirect
version can send a flash message as a third parameter, in case you’re using flash messages:
actionResult('redirect', '/', {
message: App.PageData['flash'],
status = 303
});
Login request example
src/routes/login/+server.ts
import { actionResult, superValidate } from '$lib/server';
import { z } from 'zod';
const loginSchema = z.object({
email: z.string().email(),
password: z.string().min(5)
});
export const POST = async ({ request }) => {
const form = await superValidate(request, loginSchema);
if (!form.valid) return actionResult('failure', { form });
// Verify login here //
return actionResult('success', { form });
};
Client API
import {
superForm,
intProxy,
numberProxy,
booleanProxy,
dateProxy,
fieldProxy,
formFieldProxy
} from 'sveltekit-superforms/client';
The server part of the API can also be imported, for single-page app usage:
import {
superValidate,
setError,
setMessage, // Same as message
actionResult
} from 'sveltekit-superforms/client';
superForm(form, options?)
superForm<T, M = any>(
form: Validation<T, M> | null | undefined,
options?: FormOptions<T, M>
) : SuperForm<T, M>
FormOptions<T, M> = Partial<{
id: string;
applyAction: boolean;
invalidateAll: boolean;
resetForm: boolean | (() => MaybePromise<boolean>);
scrollToError: 'auto' | 'smooth' | 'off';
autoFocusOnError: boolean | 'detect';
errorSelector: string;
selectErrorText: boolean;
stickyNavbar: string;
taintedMessage: string | false | null;
SPA: true | { failStatus?: number };
onSubmit: (
...params: Parameters<SubmitFunction>
) => MaybePromise<unknown | void>;
onResult: (event: {
result: ActionResult;
formEl: HTMLFormElement;
cancel: () => void;
}) => MaybePromise<unknown | void>;
onUpdate: (event: {
form: Validation<T, M>;
formEl: HTMLFormElement;
cancel: () => void;
}) => MaybePromise<unknown | void>;
onUpdated: (event: {
form: Readonly<Validation<T, M>>;
}) => MaybePromise<unknown | void>;
onError:
| 'apply'
| ((event: {
result: {
type: 'error';
status?: number;
error: App.Error;
};
message: Writable<Validation<T, M>['message']>;
}) => MaybePromise<unknown | void>);
dataType: 'form' | 'json';
validators: T | false | Validators<T>;
validationMethod: 'auto' | 'oninput' | 'onblur' | 'submit-only';
defaultValidator: 'keep' | 'clear';
clearOnSubmit: 'errors' | 'message' | 'errors-and-message' | 'none';
delayMs: number;
timeoutMs: number;
multipleSubmits: 'prevent' | 'allow' | 'abort';
syncFlashMessage?: boolean;
flashMessage: {
module: {
getFlash(page: Readable<Page>): Writable<App.PageData['flash']>;
updateFlash(
page: Readable<Page>,
update?: () => Promise<void>
): Promise<void>;
};
onError?: (event: {
result: {
type: 'error';
status?: number;
error: App.Error;
};
message: Writable<App.PageData['flash']>;
}) => MaybePromise<unknown | void>;
cookiePath?: string;
cookieName?: string;
};
}>;
superForm return type
SuperForm<T extends AnyZodObject, M = any> = {
form: {
subscribe: (data: S) => void
set: (value: S, options?: { taint?: boolean | 'untaint' | 'untaint-all' }) => void
update: (updater: (S) => S, options?: { taint?: boolean | 'untaint' | 'untaint-all' }) => void
};
formId: Writable<string | undefined>;
errors: Writable<Nested<S, string[] | undefined>>;
constraints: Writable<Nested<S, InputConstraints | undefined>>;
message: Writable<M | undefined>;
tainted: Writable<Nested<S, boolean | undefined> | undefined>;
meta: Readable<{ types: Record<keyof S, string> | undefined }>;
valid: Readable<boolean>;
empty: Readable<boolean>;
submitting: Readable<boolean>;
delayed: Readable<boolean>;
timeout: Readable<boolean>;
fields: Record<keyof S, FormField<T>>;
firstError: Readable<{ path: string[]; message: string } | null>;
allErrors: Readable<{ path: string[]; message: string }[]>;
options: FormOptions<T, M>;
enhance: (el: HTMLFormElement, {
onSubmit, onResult, onError, onUpdate, onUpdated
}) => ReturnType<typeof $app/forms/enhance>;
reset: (options?: { keepMessage: boolean }) => void;
capture: () => SuperFormSnapshot<T, M>;
restore: (snapshot: SuperFormSnapshot<T, M>) => void;
};
FormField<S, Prop extends keyof S> = {
readonly name: Prop;
value: Writable<S[Prop]>;
errors?: Writable<ValidationErrors<S[Prop]>>;
constraints?: Writable<InputConstraints<S[Prop]>>;
readonly type?: string;
};
Proxy objects
intProxy(form, fieldName)
Creates a proxy store for an integer schema field. Changes in either the proxy store or the form field will reflect in the other.
numberProxy(form, fieldName)
Creates a proxy store for a numeric form field.
booleanProxy(form, fieldName, options?)
Options:
{
trueStringValue = 'true';
}
Creates a proxy store for a boolean schema field. The option can be used to change what string value represents true
.
dateProxy(form, fieldName, options?)
Creates a proxy store for a Date schema field. The option can be used to change the proxied format of the date.
Options:
{
format:
// Extract the part of the date as a substring:
| 'date' | 'datetime' | 'time'
// Convert the date to UTC:
| 'date-utc' | 'datetime-utc' | 'time-utc'
// Convert the date to local time:
| 'date-local' | 'datetime-local' | 'time-local'
// The default ISODateString:
| 'iso' = 'iso'
}
fieldProxy, formFieldProxy
See the dedicated article for documentation about fieldProxy and formFieldProxy.
Proxy example
Given the following schema:
const schema = z.object({
date: z.date()
});
A date proxy can be used like this:
<script lang="ts">
import { superForm, dateProxy } from 'sveltekit-superforms/client'
import type { PageData } from './$types';
export let data: PageData;
const form = superForm(data.form)
const date = dateProxy(form, 'date', { format: 'date' ))
</script>
<input name="date" type="date" bind:value={$date} />
Components
import SuperDebug from 'sveltekit-superforms/client/SuperDebug.svelte';
SuperDebug
SuperDebug
is a debugging component that gives you colorized and nicely formatted output for any data structure, usually $form
.
<SuperDebug
data={any}
display?={true}
label?={''}
promise?={false}
status?={true}
stringTruncate?={120}
ref?={HTMLPreElement} />
Props
Prop | Type | Default value | Description |
---|---|---|---|
data | any | undefined |
Data to be displayed by SuperDebug |
display | Boolean | true |
Whether to show or hide SuperDebug |
label | String | "" |
Add useful label to SuperDebug, useful when using multiple instances of SuperDebug in a page |
promise | Boolean | false |
When true, SuperDebug uses svelte’s await block to load the data. Data is assumed to be async but can also load non-async data using await block! |
status | Boolean | true |
Whether to show or hide status code. |
stringTruncate | Number | 120 |
Truncate long string in output. |
ref | HTMLPreElement | undefined |
Binds pre tag to ref. |
Usage
Please see the +page.svelte
file in src/routes/super-debug on common usage of SuperDebug.