createValidation API Reference
Relevant source files
The following files were used as context for generating this wiki page:The createValidation function is a helper utility provided by the @opensky/remotes package designed to improve the user experience of form validation when working with SvelteKit's remote forms. It provides a reactive state management system for validation issues, with a specific logic for when to show and hide them: issues are displayed when a user leaves a field (onblur) and are cleared as soon as the user starts typing in that field again (oninput). This prevents validation errors from appearing distractingly during input.
Sources: README.md:3-8, packages/remotes/src/lib/validation.svelte.ts:10-12
This utility is often used in conjunction with its sibling helper, createEnhancedForm, which can automatically call the necessary validation functions during the form submission lifecycle.
Sources: README.md:50-52, packages/remotes/src/lib/enhance.svelte.ts:241-242, 252-253
Initialization
To use the validation helper, import createValidation and pass it a RemoteForm instance.
import { createValidation } from '@opensky/remotes';
import { myForm } from './myForm.remote';
const valid = createValidation(myForm);
Sources: README.md:13-15, packages/remotes/src/lib/validation.svelte.ts:13
The function returns a validation instance with several methods and reactive properties to manage and display form field issues.
API Methods
The object returned by createValidation contains the following methods:
| Method | Description |
|---|---|
fields(path) | Returns onblur and oninput event handlers for a given field path. This registers the path for validation. |
issues(path) | Returns a reactive array of issue strings for a field path, or null if there are no issues. |
allIssues() | Returns a reactive object containing all current validation issues for all registered fields. |
addIssue(path, issue) | Manually adds a custom validation error message to a specific field. |
reset() | Clears all validation issues from the state. |
validateAll() | Triggers validation for all registered fields against the server. |
updateIssues() | Populates the local issue state from the RemoteForm's issues for all registered fields. |
Sources: README.md:18-25, packages/remotes/src/lib/validation.svelte.ts:210-218, packages/remotes/CHANGELOG.md:7
Core Validation Logic
The primary goal of createValidation is to control the visibility of validation messages. It achieves this by providing onblur and oninput handlers via the fields(path) method.
The diagram below illustrates the user interaction flow for a single field.
fields(path: string)
This method is the main entry point for connecting a form input to the validation system. It registers the field's path and returns event handlers.
onblur: When the user leaves the field, this handler is triggered. It calls a debouncedform.validate()to check for issues. It first attempts apreflightOnlyvalidation and, if that passes, may proceed to a full server validation to get server-side issues. The resulting issues are then stored in the reactive state.oninput: When the user types in the field, this handler checks if there are existing issues for that field. If so, it triggers apreflightOnlyvalidation to see if the input is now valid. If the input becomes valid, the issues for that field are cleared from the state.
Sources: packages/remotes/src/lib/validation.svelte.ts:161-196
The onblur validation call is debounced using useDebounce from the runed library to prevent excessive network requests.
Sources: packages/remotes/src/lib/validation.svelte.ts:89-94, packages/remotes/package.json:14
The sequence diagram below shows the onblur validation process.
State Management
Internally, createValidation uses a Svelte 5 $state variable to hold the validation issues. The issues are stored in a nested object structure that mirrors the form's data structure.
type ValidationIssues = {
[key: string]: string[] | null | ValidationIssues
}
// Internal state
let issues = $state<ValidationIssues>({})
Sources: packages/remotes/src/lib/validation.svelte.ts:4-8, 14
The helper functions setNestedValue and getNestedValue are used to interact with this state object using dot-notation paths (e.g., 'address.city'). This allows the API to remain simple while supporting complex, nested form data.
Sources: packages/remotes/src/lib/validation.svelte.ts:20-41, 46-56
Integration with createEnhancedForm
While createValidation can be used standalone, it is designed to integrate with createEnhancedForm. When a validation instance is passed to createEnhancedForm, the enhance handler will automatically call updateIssues() and validateAll() at the appropriate times in the form submission lifecycle.
validation.updateIssues(): Called when a form submission returns with validation issues but no result. This ensures server-side validation messages are displayed.validation.validateAll(): Called when the form submission promise rejects (an error occurs).
This integration simplifies the process of handling server-side validation feedback.
Sources: packages/remotes/src/lib/enhance.svelte.ts:38-42, 241-242, 252-253
The following diagram shows the data flow when createValidation is used with createEnhancedForm.
Usage Example
Here is a complete example demonstrating how to use createValidation in a Svelte component.
<script lang="ts">
import { createValidation } from '@opensky/remotes';
import { myForm } from './myForm.remote';
import { z } from 'zod';
const schema = z.object({
name: z.string().min(4, 'Too short'),
address: z.object({
state: z.string()
})
});
// 1. Create the validation instance
const valid = createValidation(myForm);
</script>
<!-- 2. Preflight the form with a schema -->
<form {...myForm.preflight(schema).enhance( ... )}>
<input
{...myForm.fields.name.as('text')}
{...valid.fields('name')}
class:error={valid.issues('name')}
/>
<!-- 3. Display issues for the field -->
{#if valid.issues('name')}
{#each valid.issues('name') as issue}
<p class="error">{issue}</p>
{/each}
{/if}
<input
{...myForm.fields.address.state.as('text')}
{...valid.fields('address.state')}
class:error={valid.issues('address.state')}
/>
</form>
Sources: README.md:27-41, 114-149
This example shows how to:
- Initialize
createValidationwith a remote form. - Spread the event handlers from
valid.fields('path')onto an input element. - Conditionally display validation messages using
valid.issues('path'). - Dynamically apply a CSS class based on the presence of issues.