Making SvelteKit forms a pleasure to use with comprehensive validation, type safety, and progressive enhancement.
—
Type-safe proxy functions for binding form fields with automatic string conversion, supporting various data types including numbers, dates, booleans, arrays, and files. Enables seamless integration between Svelte's reactive system and HTML form elements.
The base field proxy function that provides type-safe binding for any form field with automatic data type conversion.
/**
* Creates a generic field proxy for type-safe form field binding
* @param form - Form store or SuperForm instance
* @param path - Path to the field in the form data structure
* @param options - Proxy configuration options
* @returns FieldProxy with get/set methods and store interface
*/
function fieldProxy<T, Path>(
form: Writable<T> | SuperForm<T>,
path: Path,
options?: ProxyOptions
): FieldProxy<FormPathType<T, Path>>;
interface FieldProxy<T> extends Writable<T> {
/** Get current field value */
get(): T;
/** Set field value and mark as tainted */
set(value: T): void;
/** Update field value with function */
update(fn: (value: T) => T): void;
/** Subscribe to field value changes */
subscribe(fn: (value: T) => void): () => void;
}
interface ProxyOptions {
/** Taint behavior when field value changes */
taint?: TaintOption;
}
type TaintOption = boolean | 'untaint' | 'untaint-all' | 'untaint-form';Usage Examples:
<script lang="ts">
import { fieldProxy } from "sveltekit-superforms/client";
export let data;
const { form } = superForm(data.form);
// Create proxy for nested field
const nameProxy = fieldProxy(form, 'user.name');
const ageProxy = fieldProxy(form, 'user.age', { taint: 'untaint' });
</script>
<input bind:value={$nameProxy} />
<input type="number" bind:value={$ageProxy} />Specialized proxies for numeric fields that handle string conversion, validation, and formatting for HTML number inputs.
/**
* Creates a proxy for integer form fields with string conversion
* @param form - Form store or SuperForm instance
* @param path - Path to the integer field
* @param options - Integer-specific options
* @returns Writable string store that syncs with integer field
*/
function intProxy<T, Path>(
form: Writable<T> | SuperForm<T>,
path: Path,
options?: {
/** How to handle empty values */
empty?: 'null' | 'undefined' | 'zero';
/** Whether empty field is initially shown as empty when value is zero */
initiallyEmptyIfZero?: boolean;
/** Taint behavior */
taint?: TaintOption;
}
): Writable<string>;
/**
* Creates a proxy for number form fields with string conversion and formatting
* @param form - Form store or SuperForm instance
* @param path - Path to the number field
* @param options - Number-specific options
* @returns Writable string store that syncs with number field
*/
function numberProxy<T, Path>(
form: Writable<T> | SuperForm<T>,
path: Path,
options?: {
/** How to handle empty values */
empty?: 'null' | 'undefined' | 'zero';
/** Decimal delimiter for display */
delimiter?: '.' | ',';
/** Whether empty field is initially shown as empty when value is zero */
initiallyEmptyIfZero?: boolean;
/** Taint behavior */
taint?: TaintOption;
}
): Writable<string>;Usage Examples:
<script lang="ts">
const { form } = superForm(data.form);
// Integer field with empty handling
const ageProxy = intProxy(form, 'age', {
empty: 'zero',
initiallyEmptyIfZero: true
});
// Decimal number with comma delimiter
const priceProxy = numberProxy(form, 'price', {
delimiter: ',',
empty: 'null'
});
</script>
<input
type="number"
bind:value={$ageProxy}
placeholder="Enter age"
/>
<input
type="number"
step="0.01"
bind:value={$priceProxy}
placeholder="0,00"
/>Proxy for boolean fields that handles checkbox and radio button interactions with customizable string representations.
/**
* Creates a proxy for boolean form fields with string conversion
* @param form - Form store or SuperForm instance
* @param path - Path to the boolean field
* @param options - Boolean-specific options
* @returns Writable string store that syncs with boolean field
*/
function booleanProxy<T, Path>(
form: Writable<T> | SuperForm<T>,
path: Path,
options?: {
/** String value representing true */
trueStringValue?: string;
/** Taint behavior */
taint?: TaintOption;
}
): Writable<string>;Usage Examples:
<script lang="ts">
const { form } = superForm(data.form);
// Standard checkbox
const agreeProxy = booleanProxy(form, 'agreed');
// Custom true value for radio buttons
const roleProxy = booleanProxy(form, 'isAdmin', {
trueStringValue: 'admin'
});
</script>
<label>
<input type="checkbox" bind:checked={$agreeProxy} />
I agree to the terms
</label>
<label>
<input
type="radio"
name="role"
value="admin"
bind:group={$roleProxy}
/>
Administrator
</label>Specialized proxy for date fields supporting various date formats and timezone handling for HTML date/time inputs.
/**
* Creates a proxy for date form fields with format conversion
* @param form - Form store or SuperForm instance
* @param path - Path to the date field
* @param options - Date-specific options
* @returns Writable string store that syncs with date field
*/
function dateProxy<T, Path>(
form: Writable<T> | SuperForm<T>,
path: Path,
options?: {
/** Date format for HTML input compatibility */
dateFormat?:
| 'date' // YYYY-MM-DD
| 'datetime' // YYYY-MM-DDTHH:mm
| 'time' // HH:mm
| 'date-utc' // UTC date
| 'datetime-utc' // UTC datetime
| 'time-utc' // UTC time
| 'date-local' // Local date
| 'datetime-local' // Local datetime
| 'time-local' // Local time
| 'iso'; // Full ISO string
/** Taint behavior */
taint?: TaintOption;
}
): Writable<string>;Usage Examples:
<script lang="ts">
const { form } = superForm(data.form);
// Date input
const birthdateProxy = dateProxy(form, 'birthdate', {
dateFormat: 'date'
});
// Datetime-local input
const appointmentProxy = dateProxy(form, 'appointment', {
dateFormat: 'datetime-local'
});
// Time input
const timeProxy = dateProxy(form, 'meetingTime', {
dateFormat: 'time'
});
</script>
<input type="date" bind:value={$birthdateProxy} />
<input type="datetime-local" bind:value={$appointmentProxy} />
<input type="time" bind:value={$timeProxy} />Advanced proxy for array fields that provides methods for adding, removing, and reordering array items with type safety.
/**
* Creates a proxy for array form fields with manipulation methods
* @param form - Form store or SuperForm instance
* @param path - Path to the array field
* @param options - Array-specific options
* @returns ArrayProxy with array manipulation methods
*/
function arrayProxy<T, Path>(
form: Writable<T> | SuperForm<T>,
path: Path,
options?: ProxyOptions
): ArrayProxy<T, Path>;
interface ArrayProxy<T, Path> extends Writable<FormPathType<T, Path>[]> {
/** Add new item to the end of array */
push(item: FormPathType<T, Path>): void;
/** Remove and return last item from array */
pop(): FormPathType<T, Path> | undefined;
/** Add new item to the beginning of array */
unshift(item: FormPathType<T, Path>): void;
/** Remove and return first item from array */
shift(): FormPathType<T, Path> | undefined;
/** Insert item at specific index */
insert(index: number, item: FormPathType<T, Path>): void;
/** Remove item at specific index */
remove(index: number): FormPathType<T, Path> | undefined;
/** Move item from one index to another */
move(fromIndex: number, toIndex: number): void;
/** Replace item at specific index */
replace(index: number, item: FormPathType<T, Path>): void;
/** Clear all items from array */
clear(): void;
/** Get current array length */
length: Readable<number>;
}Usage Examples:
<script lang="ts">
const { form } = superForm(data.form);
const tagsProxy = arrayProxy(form, 'tags');
function addTag() {
$tagsProxy = [...$tagsProxy, ''];
}
function removeTag(index: number) {
tagsProxy.remove(index);
}
</script>
{#each $tagsProxy as tag, i}
<div class="tag-input">
<input bind:value={$tagsProxy[i]} placeholder="Enter tag" />
<button type="button" on:click={() => removeTag(i)}>Remove</button>
</div>
{/each}
<button type="button" on:click={addTag}>Add Tag</button>Specialized proxies for file upload fields supporting single and multiple file handling with validation and metadata access.
/**
* Creates a proxy for single file upload fields
* @param form - Form store or SuperForm instance
* @param path - Path to the file field
* @param options - File-specific options
* @returns Writable store for File objects
*/
function fileProxy<T, Path>(
form: Writable<T> | SuperForm<T>,
path: Path,
options?: ProxyOptions
): Writable<File | null>;
/**
* Creates a proxy for single file upload fields with form integration
* @param form - SuperForm instance
* @param path - Path to the file field
* @param options - File-specific options with validation
* @returns FormFieldProxy with file handling
*/
function fileFieldProxy<T, Path>(
form: SuperForm<T>,
path: Path,
options?: ProxyOptions
): FormFieldProxy<T, Path>;
/**
* Creates a proxy for multiple file upload fields
* @param form - Form store or SuperForm instance
* @param path - Path to the files field
* @param options - Files-specific options
* @returns Writable store for FileList or File arrays
*/
function filesProxy<T, Path>(
form: Writable<T> | SuperForm<T>,
path: Path,
options?: ProxyOptions
): Writable<FileList | File[] | null>;
/**
* Creates a proxy for multiple file upload fields with form integration
* @param form - SuperForm instance
* @param path - Path to the files field
* @param options - Files-specific options with validation
* @returns FormFieldProxy with multiple file handling
*/
function filesFieldProxy<T, Path>(
form: SuperForm<T>,
path: Path,
options?: ProxyOptions
): FormFieldProxy<T, Path>;
interface FormFieldProxy<T, Path> extends FieldProxy<FormPathType<T, Path>> {
/** Field validation errors */
errors: Readable<string[]>;
/** Field constraints */
constraints: Readable<InputConstraint>;
/** Whether field is tainted */
tainted: Readable<boolean>;
}Usage Examples:
<script lang="ts">
const { form } = superForm(data.form);
// Single file upload
const avatarProxy = fileProxy(form, 'avatar');
// Multiple file upload with field integration
const documentsProxy = filesFieldProxy(form, 'documents');
$: console.log('Avatar:', $avatarProxy?.name, $avatarProxy?.size);
$: console.log('Documents:', $documentsProxy?.length);
</script>
<!-- Single file -->
<input
type="file"
accept="image/*"
on:change={(e) => $avatarProxy = e.target.files?.[0] || null}
/>
<!-- Multiple files with validation -->
<input
type="file"
multiple
accept=".pdf,.doc,.docx"
bind:files={$documentsProxy}
/>
{#if $documentsProxy.errors.length > 0}
<div class="errors">
{#each $documentsProxy.errors as error}
<p class="error">{error}</p>
{/each}
</div>
{/if}Basic proxy for string fields with customizable behavior and validation integration.
/**
* Creates a proxy for string form fields
* @param form - Form store or SuperForm instance
* @param path - Path to the string field
* @param options - String-specific options
* @returns Writable string store
*/
function stringProxy<T, Path>(
form: Writable<T> | SuperForm<T>,
path: Path,
options?: ProxyOptions
): Writable<string>;
/**
* Creates a proxy for string form fields with form integration
* @param form - SuperForm instance
* @param path - Path to the string field
* @param options - String-specific options with validation
* @returns FormFieldProxy with string handling
*/
function formFieldProxy<T, Path>(
form: SuperForm<T>,
path: Path,
options?: ProxyOptions
): FormFieldProxy<T, Path>;Usage Examples:
<script lang="ts">
const { form } = superForm(data.form);
// Basic string proxy
const nameProxy = stringProxy(form, 'name');
// String proxy with validation integration
const emailProxy = formFieldProxy(form, 'email');
</script>
<input bind:value={$nameProxy} />
<input
type="email"
bind:value={$emailProxy}
class:error={$emailProxy.errors.length > 0}
/>
{#if $emailProxy.errors.length > 0}
<span class="error">{$emailProxy.errors[0]}</span>
{/if}interface FieldProxy<T> extends Writable<T> {
/** Get current field value */
get(): T;
/** Set field value */
set(value: T): void;
/** Update field value with function */
update(fn: (value: T) => T): void;
/** Subscribe to value changes */
subscribe(fn: (value: T) => void): () => void;
}
interface FormFieldProxy<T, Path> extends FieldProxy<FormPathType<T, Path>> {
/** Field validation errors */
errors: Readable<string[]>;
/** HTML input constraints */
constraints: Readable<InputConstraint>;
/** Whether field has been modified */
tainted: Readable<boolean>;
}
interface ArrayProxy<T, Path> extends Writable<FormPathType<T, Path>[]> {
/** Array manipulation methods */
push(item: FormPathType<T, Path>): void;
pop(): FormPathType<T, Path> | undefined;
unshift(item: FormPathType<T, Path>): void;
shift(): FormPathType<T, Path> | undefined;
insert(index: number, item: FormPathType<T, Path>): void;
remove(index: number): FormPathType<T, Path> | undefined;
move(fromIndex: number, toIndex: number): void;
replace(index: number, item: FormPathType<T, Path>): void;
clear(): void;
/** Array length as readable store */
length: Readable<number>;
}
interface ProxyOptions {
/** Taint configuration */
taint?: TaintOption;
}
interface InputConstraint {
/** Minimum value/length */
min?: number;
/** Maximum value/length */
max?: number;
/** Step value for numbers */
step?: number;
/** Minimum string length */
minlength?: number;
/** Maximum string length */
maxlength?: number;
/** Regular expression pattern */
pattern?: string;
/** Whether field is required */
required?: boolean;
}
type TaintOption = boolean | 'untaint' | 'untaint-all' | 'untaint-form';
type FormPath<T, Type = any> = string; // String path to field in T
type FormPathType<T, Path extends string> = any; // Type at path in TInstall with Tessl CLI
npx tessl i tessl/npm-sveltekit-superforms