Making SvelteKit forms a pleasure to use with comprehensive validation, type safety, and progressive enhancement.
npx @tessl/cli install tessl/npm-sveltekit-superforms@2.27.0SvelteKit Superforms is a comprehensive form handling library that makes form validation, data binding, and error management a pleasure to use in SvelteKit applications. It provides type-safe form handling with progressive enhancement, supporting 12+ validation libraries and offering seamless client-server integration.
npm install sveltekit-superformsimport { superForm, superValidate } from "sveltekit-superforms";
import { zod } from "sveltekit-superforms/adapters";
import { z } from "zod";For client-only imports:
import { superForm } from "sveltekit-superforms/client";For server-only imports:
import { superValidate, message, setError } from "sveltekit-superforms/server";// schema.ts
import { z } from "zod";
export const schema = z.object({
name: z.string().min(2),
email: z.string().email(),
age: z.number().min(18)
});
// +page.server.ts
import { superValidate } from "sveltekit-superforms/server";
import { zod } from "sveltekit-superforms/adapters";
import { schema } from "./schema.js";
export const load = async () => {
const form = await superValidate(zod(schema));
return { form };
};
export const actions = {
default: async ({ request }) => {
const form = await superValidate(request, zod(schema));
if (!form.valid) {
return fail(400, { form });
}
// Process valid form data
console.log(form.data);
return { form };
}
};
// +page.svelte
<script lang="ts">
import { superForm } from "sveltekit-superforms/client";
export let data;
const { form, errors, enhance } = superForm(data.form);
</script>
<form method="POST" use:enhance>
<input name="name" bind:value={$form.name} />
{#if $errors.name}<span class="error">{$errors.name}</span>{/if}
<input name="email" type="email" bind:value={$form.email} />
{#if $errors.email}<span class="error">{$errors.email}</span>{/if}
<input name="age" type="number" bind:value={$form.age} />
{#if $errors.age}<span class="error">{$errors.age}</span>{/if}
<button type="submit">Submit</button>
</form>SvelteKit Superforms is built around several key architectural components:
superValidate function for server-side form processing and validationsuperForm function creating reactive Svelte stores for form stateComplete server-side form processing with validation, error handling, and data coercion. Handles form submissions, file uploads, and integrates with SvelteKit's action system.
function superValidate<Out, Message, In>(
adapter: ValidationAdapter<Out, In>,
options?: SuperValidateOptions<Out>
): Promise<SuperValidated<Out, Message, In>>;
function superValidate<Out, Message, In>(
data: RequestEvent | Request | FormData | URLSearchParams | URL | Partial<In> | null | undefined,
adapter: ValidationAdapter<Out, In>,
options?: SuperValidateOptions<Out>
): Promise<SuperValidated<Out, Message, In>>;Reactive form management with Svelte stores, real-time validation, error handling, and progressive enhancement features.
function superForm<T, M>(
form: SuperValidated<T, M>,
options?: FormOptions<T, M>
): SuperForm<T, M>;
interface SuperForm<T, M> {
form: SuperFormData<T>;
formId: Writable<string>;
errors: SuperFormErrors<T>;
constraints: Writable<InputConstraints<T>>;
message: Writable<M | undefined>;
tainted: Writable<TaintedFields<T> | undefined>;
submitting: Readable<boolean>;
delayed: Readable<boolean>;
timeout: Readable<boolean>;
posted: Readable<boolean>;
allErrors: Readable<{ path: string; messages: string[] }[]>;
enhance: (el: HTMLFormElement, events?: SuperFormEvents<T, M>) => ReturnType<SubmitFunction>;
isTainted: (path?: FormPath<T> | Record<string, unknown> | boolean | undefined) => boolean;
reset: (options?: ResetOptions<T>) => void;
submit: (submitter?: HTMLElement | Event | EventTarget | null) => void;
validate: <Path extends FormPathLeaves<T>>(path: Path, opts?: ValidateOptions<FormPathType<T, Path>, Partial<T>, Record<string, unknown>>) => Promise<string[] | undefined>;
validateForm: <P extends Partial<T> = T>(opts?: { update?: boolean; schema?: ValidationAdapter<P>; focusOnError?: boolean; }) => Promise<SuperFormValidated<T, M>>;
capture: () => SuperFormSnapshot<T, M>;
restore: (snapshot: SuperFormSnapshot<T, M>) => void;
// ... other methods and properties documented in detail in sub-docs
}Type-safe proxy functions for binding form fields with automatic string conversion, supporting various data types including numbers, dates, booleans, arrays, and files.
function fieldProxy<T, Path>(
form: Writable<T> | SuperForm<T>,
path: Path,
options?: ProxyOptions
): FieldProxy<FormPathType<T, Path>>;
function intProxy<T, Path>(
form: Writable<T> | SuperForm<T>,
path: Path,
options?: ProxyOptions
): Writable<string>;
function dateProxy<T, Path>(
form: Writable<T> | SuperForm<T>,
path: Path,
options?: { dateFormat?: 'date' | 'datetime' | 'time' | 'iso'; taint?: TaintOption }
): Writable<string>;Unified adapters for 12+ popular validation libraries, providing consistent interface and type inference across different schema validation approaches.
function zod<T>(
schema: ZodObjectType<T>,
options?: AdapterOptions<T>
): ValidationAdapter<T>;
function yup<T>(
schema: YupSchema<T>,
options?: AdapterOptions<T>
): ValidationAdapter<T>;
function joi<T>(
schema: JoiSchema<T>,
options?: AdapterOptions<T>
): ValidationAdapter<T>;
// ... and 9 more adaptersinterface SuperValidated<Out, Message = any, In = Out> {
id: string;
valid: boolean;
posted: boolean;
errors: ValidationErrors<Out>;
data: Out;
constraints?: InputConstraints<Out>;
message?: Message;
shape?: SchemaShape;
}
interface ValidationErrors<T> {
_errors?: string[];
[K in keyof T]?: T[K] extends Record<string, unknown>
? ValidationErrors<T[K]>
: T[K] extends Array<infer U>
? U extends Record<string, unknown>
? Array<ValidationErrors<U> | undefined>
: string[]
: string[];
}
interface FormOptions<T, M, In = T> {
id?: string;
applyAction?: boolean | 'never';
invalidateAll?: boolean | 'force' | 'pessimistic';
resetForm?: boolean | (() => boolean);
scrollToError?: 'auto' | 'smooth' | 'off' | boolean | ScrollIntoViewOptions;
autoFocusOnError?: boolean | 'detect';
errorSelector?: string;
selectErrorText?: boolean;
stickyNavbar?: string;
taintedMessage?: string | boolean | null | ((nav: BeforeNavigate) => Promise<boolean>);
spa?: boolean | { failover?: boolean };
dataType?: 'form' | 'json';
validators?: ValidationAdapter<Partial<T>> | ClientValidationAdapter<Partial<T>> | false | 'clear';
customValidity?: boolean;
clearOnSubmit?: 'errors' | 'message' | 'errors-and-message' | 'none';
multipleSubmits?: 'prevent' | 'allow' | 'abort';
SPA?: { failover?: boolean };
flashMessage?: {
module: { getFlash(page: Page): FlashMessage };
onError?: ({ result, message }: { result: ActionResult; message: FlashMessage }) => void;
};
onError?: (event: { result: ActionResult; message?: any }) => void;
onResult?: (event: { result: ActionResult; formEl: HTMLFormElement; cancel: () => void }) => void;
onSubmit?: (event: { formData: FormData; formElement: HTMLFormElement; controller: AbortController; cancel: () => void }) => void;
onUpdate?: (event: { form: SuperValidated<T, M>; formEl: HTMLFormElement; cancel: () => void }) => void;
onUpdated?: (event: { form: SuperValidated<T, M>; formEl: HTMLFormElement }) => void;
}
type ValidationAdapter<Out, In = Out> = {
superFormValidationLibrary: ValidationLibrary;
validate: (data: unknown) => Promise<ValidationResult<Out>>;
jsonSchema: JSONSchema;
defaults: Out;
constraints: InputConstraints<Out>;
shape: SchemaShape;
id: string;
};
type FormPath<T, Type = any> = string; // Path to any property in T
type FormPathLeaves<T, Type = any> = string; // Path to leaf properties only
type FormPathType<T, Path extends string> = any; // Type at path in T
type TaintedFields<T> = {
[K in keyof T]?: T[K] extends Record<string, unknown>
? TaintedFields<T[K]>
: T[K] extends Array<any>
? boolean[]
: boolean;
};
type Infer<T> = T; // Infer output type from schema
type InferIn<T> = T; // Infer input type from schema