Server-Side Validation Flow
Relevant source files
The following files were used as context for generating this wiki page:The @opensky/remotes package provides helper utilities to enhance the developer and user experience when working with SvelteKit's remote form functions. The server-side validation flow is primarily managed by two core helpers: createValidation and createEnhancedForm. These work in tandem to provide reactive state management for validation issues, handle the form submission lifecycle, and intelligently interact with the server to fetch and display validation feedback.
This system is designed to improve the default behavior of forms by implementing a common UX pattern: validation issues for a field appear when the user leaves the field (onblur) but are cleared as soon as the user starts typing again (oninput). This prevents distracting validation messages from appearing mid-typing while still providing immediate feedback. The helpers also manage the state transitions during form submission, including handling successful results, server-side validation issues, and network errors.
Sources: README.md:3-11, packages/remotes/src/lib/index.ts
Core Components
The validation flow is built upon two main functions exported by the package.
Sources: packages/remotes/src/lib/index.ts:1-2
createValidation
This helper is responsible for managing the state of validation issues for form fields. It creates a reactive issues object and provides functions to interact with it. It attaches onblur and oninput event handlers to fields to trigger validation and update the UI accordingly. It uses Svelte 5 runes ($state) for reactivity and runed's useDebounce to prevent excessive validation calls to the server.
Sources: packages/remotes/src/lib/validation.svelte.ts:11-14, 80-86, packages/remotes/package.json:15-17
createEnhancedForm
This helper manages the entire form submission lifecycle. It creates a state machine that tracks the form's status (e.g., idle, pending, issues, error). It integrates with an instance of createValidation to automatically call the correct validation functions (updateIssues or validateAll) based on the server's response, thus connecting the form's state to the validation state.
Sources: packages/remotes/src/lib/enhance.svelte.ts:22-28, 260-264, 271-273, README.md:65-71
The diagram below shows how the two components are instantiated and used together in a Svelte component.
Sources: README.md:120-134
createValidation API
The createValidation function returns an object with several methods to manage and access validation state.
| Method | Description |
|---|---|
fields(path) | Returns onblur and oninput handlers for a given field path. Registers the path for validation. |
issues(path) | Returns an array of validation issue strings for a field path, or null if none. |
allIssues() | Returns the entire tree of validation issues. |
addIssue(path, issue) | Manually adds a custom validation error to a field, useful for client-side checks. |
reset() | Clears all validation issues from the state. |
validateAll() | Triggers validation for all registered fields against the server. |
updateIssues() | Populates the local issues state from the RemoteForm's current issues, typically after a server round-trip. |
Sources: README.md:16-24, packages/remotes/src/lib/validation.svelte.ts:205-214, CHANGELOG.md:7-9
Validation Lifecycle
The validation process is split into two main parts: real-time feedback at the field level and state updates after a full form submission.
Field-Level Validation (onblur / oninput)
The valid.fields(path) function provides event handlers that implement the core UX logic.
onblur: When a user leaves a field, a debounced remote validation is triggered. It first attempts apreflightvalidation. If that passes, it may perform a full server validation to catch more complex errors. The resulting issues are then stored in the reactiveissuesstate.oninput: When a user starts typing in a field that has an error, apreflightOnlyvalidation is triggered. As the user corrects the input, the validation passes, and the issue is cleared from the state, providing instant feedback.
Sources: packages/remotes/src/lib/validation.svelte.ts:153-190, README.md:7-9
The following diagram illustrates the logic within the onblur and oninput handlers.
Full Form Submission and Server Feedback
When the form is submitted, createEnhancedForm orchestrates the interaction with the server and updates the validation state based on the outcome.
- On Validation Issues: If the server returns validation errors (the form submission does not return a
resultbut has issues),createEnhancedFormsets its state to'issues'. It then callsvalidation.updateIssues(), which reads the errors from theRemoteFormobject and populates the localissuesstate, causing the UI to display the errors next to the corresponding fields. - On Other Errors: If the submission throws an exception (e.g., network error, server crash), the state becomes
'error', andcreateEnhancedFormcallsvalidation.validateAll()to re-validate the form data, which may reveal issues that were not caught by preflight checks.
Sources: packages/remotes/src/lib/enhance.svelte.ts:258-273, README.md:57-61
This sequence diagram shows the complete flow from submission to displaying server-side validation issues.
State Management with createEnhancedForm
The createEnhancedForm helper provides a robust state machine to track the form's lifecycle. The state is reactive and can be used to drive the UI (e.g., disabling buttons, showing spinners).
Sources: packages/remotes/src/lib/enhance.svelte.ts:208-211, README.md:65-67
The possible states are determined by the options passed at creation time. The delayed and timeout states are only available if delayMs and timeoutMs are configured, respectively.
Sources: CHANGELOG.md:12-15, commit-message.txt:4-12
Form States
| State | Description |
|---|---|
idle | The form is waiting for submission. |
pending | The form has been submitted and is awaiting a response. |
delayed | The submission is taking longer than delayMs. (Conditional) |
timeout | The submission has exceeded the timeoutMs. (Conditional) |
issues | The server responded with validation issues. |
error | The submission resulted in an unhandled error or exception. |
result | The server responded with a successful result. (Formerly success). |
Sources: packages/remotes/src/lib/enhance.svelte.ts:40-45, 335-349, CHANGELOG.md:10
Lifecycle Callbacks
createEnhancedForm provides callbacks that are executed at different stages of the submission lifecycle, allowing for custom logic.
| Callback | Trigger |
|---|---|
onSubmit | Called immediately when the form submission begins. |
onDelay | Called if the submission enters the delayed state. |
onTimeout | Called if the submission enters the timeout state. |
onReturn | Called when the submission is successful and returns a result. |
onIssues | Called when the submission returns with validation issues. |
onError | Called when the submission encounters an error. |
Sources: README.md:86-95, packages/remotes/src/lib/enhance.svelte.ts:100-111
Conclusion
The server-side validation flow in @opensky/remotes is a well-structured system that enhances SvelteKit's remote forms. By combining createValidation for fine-grained, reactive issue management with createEnhancedForm for lifecycle and state orchestration, it provides a robust and user-friendly solution. The clear separation of concerns allows developers to easily implement complex validation logic that feels responsive on the client-side while being backed by the authority of the server. The integration is seamless, automatically handling the communication between the form's state and the validation UI based on server responses.
Sources: README.md:3-5, packages/remotes/src/lib/enhance.svelte.ts:22-28