This is a validation library for SvelteKit, integrating Valibot to simplify validation on both front and backend. This library provides reusable form components, context-aware validation, and error handling.
Install the library using npm:
npm install svelte-valibot-form
Make sure to install its dependencies:
npm install valibot
To create a form that validates data based on a schema, import ValibotForm and pass the necessary schema. Here’s a basic login form example:
<!-- +page.svelte -->
<script lang="ts">
import FileInput from '$lib/components/FileInput.svelte';
import GenericInput from '$lib/components/GenericInput.svelte';
import ValibotForm from '$lib/components/ValibotForm.svelte';
import { ValibotAction } from '$lib/index.js';
import { LoginSchema, type LoginSchemaType } from '$lib/schema/LoginSchema.js';
import type { InferOutput } from 'valibot';
const login = async (data: InferOutput<LoginSchemaType>) => await ValibotAction.call('login', LoginSchema, data);
</script>
<ValibotForm
schema={LoginSchema}
defaultValues={{ email: '', password: 'teste', file: [new File([], 'test.png')] }}
onSubmit={login}
onError={console.log}
>
<GenericInput name="email" type="email" placeholder="Email" />
<GenericInput name="password" type="password" placeholder="Password" />
<FileInput name="file" multiple />
<button type="submit">Login</button>
</ValibotForm>
To access validation errors and default values directly within your form elements, use getContext to retrieve the validation context.
<script lang="ts">
import { getContext } from 'svelte';
import type { LoginSchemaType } from '$lib/schema/LoginSchema.js';
import type { ValibotErrorContext, ValibotErrorKey } from '$lib/types.js';
const props: SvelteHTMLElements['input'] = $props();
const ctx = getContext<ValibotErrorContext<LoginSchemaType>>('form');
const key = props.name as ValibotErrorKey<LoginSchemaType>;
const defaultValue = ctx?.defaultValues?.[key];
const error = ctx?.errors?.[key];
let files: FileList | null = $state(null);
$effect(() => {
if (defaultValue) {
const dt = new DataTransfer();
Array.isArray(defaultValue) ? defaultValue.forEach((file) => dt.items.add(file)) : dt.items.add(defaultValue);
files = dt.files;
}
});
</script>
<div>
<input type="file" bind:files {...props} />
{#if error}
<p>{error}</p>
{/if}
</div>
<script lang="ts">
import { getContext } from 'svelte';
import type { SvelteHTMLElements } from 'svelte/elements';
const props: SvelteHTMLElements['input'] = $props();
import type { LoginSchemaType } from '$lib/schema/LoginSchema.js';
import type { ValibotErrorContext, ValibotErrorKey } from '$lib/types.js';
const key = props.name as ValibotErrorKey<LoginSchemaType>;
const ctx = getContext<ValibotErrorContext<LoginSchemaType>>('form');
const value = ctx?.defaultValues?.[key];
const error = $derived(ctx?.errors?.[key]);
</script>
<div>
<input {value} {...props} />
{#if error}
<p>{error}</p>
{/if}
</div>
On the server side, simply parse incoming form data using the ValibotAction wrapper function with the schema to validate the data.
The return object of the Action will have a new member called data that has all the submitted data.
// +page.server.ts
import { withValibot } from '$lib/request/WithSchema.js';
import { LoginSchema } from '$lib/schema/LoginSchema.js';
import type { Actions } from './$types.js';
export const actions: Actions = {
login: withValibot(LoginSchema, async ({ data, request }) => {
console.log(request);
console.log(data);
})
};
The ValibotForm component accepts the following props:
type ValibotFormProps = SvelteHTMLElements['form'] & {
schema: Schema;
forceSubmit?: boolean;
defaultValues?: Partial<v.InferInput<Schema>>;
onSubmit?: (values: v.InferOutput<Schema>) => void;
onError?: (errors: [v.InferIssue<Schema>, ...v.InferIssue<Schema>[]]) => void;
};
Each form element can access validation context properties such as defaultValues and errors using getContext.
const ctx = getContext<ValibotErrorContext<LoginSchemaType>>('form');
Here’s a complete example to illustrate the library’s usage.
<script lang="ts">
import ValibotForm from '$lib/components/ValibotForm.svelte';
import GenericInput from '$lib/components/GenericInput.svelte';
import { LoginSchema, type LoginSchemaType } from '$lib/schema/LoginSchema.js';
import { ValibotAction } from '$lib/index.js';
import type { InferOutput } from 'valibot';
const login = async (data: InferOutput<LoginSchemaType>) => await ValibotAction.call('login', LoginSchema, data);
</script>
<ValibotForm schema={LoginSchema} defaultValues={{ email: '', password: '' }} onSubmit={login} onError={console.error}>
<GenericInput name="email" type="email" placeholder="Email" />
<GenericInput name="password" type="password" placeholder="Password" />
<button type="submit">Login</button>
</ValibotForm>
The ValibotAction class is a utility for submitting validated form data directly to server actions in SvelteKit.
It allows for seamless form submission, including handling file uploads, transforming the form data, and validating inputs against a Valibot schema before sending to the server.
ValibotAction.call validates the input data with the provided Valibot schema. If validation succeeds, it converts the data into FormData, handling nested objects and file uploads.
Then, it sends the data to the specified server action endpoint. If the invalidate option is set, the cache will be invalidated after a successful submission.
In a form component, ValibotAction.call can be used to validate and send form data:
import { ValibotAction } from '$lib/index.js';
import { LoginSchema, type LoginSchemaType } from '$lib/schema/LoginSchema.js';
import type { InferOutput } from 'valibot';
const login = async (data: InferOutput<LoginSchemaType>) => await ValibotAction.call('login', LoginSchema, data);
ValibotAction.callstatic async call<Schema extends GenericValibotObject>(
action: string,
schema: Schema,
data: InferInput<Schema>,
options?: ActionOptions
): Promise<{ success: boolean; errors?: Record<string, string>; issues?: ValibotIssue[] }>
action (string): Name of the server action to invoke.
schema (GenericValibotObject): A Valibot schema defining validation rules for the data.
data (InferInput
options (ActionOptions, optional): Additional options, including:
invalidate (boolean): If true, invalidates the client-side cache after successful submission. Defaults to true.Returns: An object containing:
success (boolean): Indicates if the validation and submission were successful.errors (optional): An error map generated if validation fails.issues (optional): Array of Valibot validation issues if validation fails.This project is licensed under the MIT License.
This README provides a structured overview of your Valibot SvelteKit library, detailing the setup and usage of key components, properties, and context, with example code snippets. Let me know if you'd like further customization!