Search for a command to run...
Last updated June 9, 2026
The useCtrovalidate function returns Svelte stores (writable/derived) for form state, errors, dirty tracking, and async validation status. Integrates with ctrovalidate-core's validateAsync.
useCtrovalidate<T>(options)function useCtrovalidate<T extends object>(options: UseCtrovalidateOptions<T>): {
values: Writable<T>;
errors: Writable<Partial<Record<keyof T, string>>>;
isDirty: Writable<Partial<Record<keyof T, boolean>>>;
isValidating: Writable<Partial<Record<keyof T, boolean>>>;
isValid: Readable<boolean>;
validateField: (name: keyof T, value?: T[keyof T]) => Promise<boolean>;
validateForm: () => Promise<boolean>;
reset: (newValues?: Partial<T>) => void;
handleChange: (name: keyof T, value: T[keyof T]) => void;
handleBlur: (name: keyof T) => void;
}interface UseCtrovalidateOptions<T extends object> {
schema: ValidationSchema;
initialValues?: T;
validateOnBlur?: boolean;
validateOnChange?: boolean;
customRules?: Record<string, RuleLogic | AsyncRuleLogic>;
aliases?: Record<string, SchemaRule>;
messages?: Record<string, string>;
locale?: string;
}| Option | Type | Default | Description |
|---|---|---|---|
schema | ValidationSchema | — | (Required) Field-to-rules mapping |
initialValues | T | {} | Initial form state |
validateOnBlur | boolean | true | Validate when handleBlur is called |
validateOnChange | boolean | true | Validate when handleChange is called |
customRules | Record<string, RuleLogic | AsyncRuleLogic> | {} | Custom rules merged over built-ins |
aliases | Record<string, SchemaRule> | {} | Named rule combinations |
messages | Record<string, string> | {} | Custom error messages |
locale | string | — | Override locale for translator |
$ prefix in templates)| Store | Type | Description |
|---|---|---|
values | Writable<T> | Current form values. Updated via handleChange or manually with .update()/.set() |
errors | Writable<Partial<Record<keyof T, string>>> | Error messages per field. undefined means valid. Pre-initialized with all schema keys |
isDirty | Writable<Partial<Record<keyof T, boolean>>> | Track which fields have been interacted with |
isValidating | Writable<Partial<Record<keyof T, boolean>>> | Track which fields have in-flight async validation |
isValid | Readable<boolean> | Derived store — true when no field has a truthy error string |
| Method | Signature | Description |
|---|---|---|
validateField | (name: keyof T, value?: T[keyof T]) => Promise<boolean> | Validate a single field. Uses provided value or current store value |
validateForm | () => Promise<boolean> | Validate all schema fields. Updates errors store |
reset | (newValues?: Partial<T>) => void | Reset to initialValues (merged with newValues). Clears errors, dirty, validating |
handleChange | (name: keyof T, value: T[keyof T]) => void | Update value, mark dirty, validate (if validateOnChange) |
handleBlur | (name: keyof T) => void | Mark dirty, validate (if validateOnBlur) |
handleChange(name, value)<input value={$values.email} on:input={(e) => handleChange('email', e.target.value)} />values store via .update()isDirty[name] = truevalidateField(name) if validateOnChange is enabledhandleBlur(name)<input on:blur={() => handleBlur('email')} />isDirty[name] = truevalidateField(name) if validateOnBlur is enabledvalidateField(name, value?)true if no schema rule exists for the fieldAbortController)isValidating[name] = truevalidateAsync with the field value and signalerrors[name] to error string (or undefined if valid)isValidating[name] = falsetrue if validIf the async rule throws AbortError, returns false silently. Other errors are logged and return false.
validateForm()values via get(values)validateAsync with full data and schemaerrors store with fresh resultstrue only if every field passesreset(newValues?)Re-initializes all stores: values to merged initialValues + newValues, errors/dirty/validating to fresh objects with all schema keys set to undefined/false.
Each field has its own AbortController stored in a closure. When validateField is called again before the previous call completes, the old controller is aborted. All controllers are aborted on component destroy via onDestroy.
handleChange + handleBlur<script lang="ts">
const { values, errors, handleChange, handleBlur, validateForm } =
useCtrovalidate<{ email: string }>({
initialValues: { email: '' },
schema: { email: 'required|email' },
});
</script>
<input
value={$values.email}
on:input={(e) => handleChange('email', e.target.value)}
on:blur={() => handleBlur('email')}
/>
{#if $errors.email}
<span>{$errors.email}</span>
{/if}<input
value={$values.email}
on:input={(e) => $values.email = e.target.value}
/>Note: Direct store mutation does NOT mark the field dirty or trigger validation. Use handleChange for automatic validation.
import { useCtrovalidate } from 'ctrovalidate-svelte';
import type { UseCtrovalidateOptions } from 'ctrovalidate-svelte';| Import | Kind |
|---|---|
useCtrovalidate | Function |
UseCtrovalidateOptions | Type (inline in source, exported implicitly) |