Using Lifecycle Callbacks
Relevant source files
The following files were used as context for generating this wiki page:The @opensky/remotes package provides a createEnhancedForm helper to augment SvelteKit's native remote form functionality. It introduces tracked state and a series of semantic lifecycle callbacks that simplify handling the various stages of a form submission. This allows for more declarative and robust management of UI state, optimistic updates, and error handling, similar to the experience provided by libraries like superforms.
This utility wraps a standard RemoteForm instance, exposing an enhance method that accepts a set of callbacks. These callbacks are invoked at specific points in the form submission lifecycle, from initial submission to the final result, error, or validation issue state. This structured approach helps manage side effects like showing loaders, displaying timeout messages, and integrating with validation logic.
Sources: README.md, packages/remotes/src/lib/enhance.svelte.ts
Core Concept: createEnhancedForm
The foundation of the lifecycle callback system is the createEnhancedForm function. It takes a RemoteForm instance and an optional configuration object to create an enhanced form manager. This manager tracks the submission state and provides the enhance method to hook into the lifecycle.
Sources: packages/remotes/src/lib/index.ts:2, README.md:58-64
Creation Options
The behavior of the enhanced form can be configured at creation time. The timing options (delayMs, timeoutMs) were moved from the enhance call to the creation function to enable type-safe conditional states.
| Option | Type | Description |
|---|---|---|
validation | Validation | An optional instance from createValidation to automatically handle validation issue updates. |
delayMs | number | Milliseconds to wait before the form state transitions to delayed. If provided, the delayed state and onDelay callback become available. |
timeoutMs | number | Milliseconds to wait before the form state transitions to timeout. If provided, the timeout state and onTimeout callback become available. |
Sources: packages/remotes/src/lib/enhance.svelte.ts:46-55, packages/remotes/CHANGELOG.md:14-16, commit-message.txt:4-6
The Form Submission Lifecycle
createEnhancedForm manages a state machine that represents the current stage of the form submission. This state is reactive and can be used to drive the UI.
The following diagram illustrates the possible state transitions during a form submission.
This diagram shows the flow of states from idle through pending and potentially delayed or timeout, before resolving to a final state of result, issues, or error.
Sources: packages/remotes/src/lib/enhance.svelte.ts:31, packages/remotes/src/lib/enhance.svelte.ts:258-261
Form States
The enhanced form provides boolean getters to easily check the current state. The delayed and timeout getters are conditionally available based on the options provided at creation.
| State/Getter | Type | Description |
|---|---|---|
state | string | The raw string value of the current state (e.g., 'idle', 'pending'). |
idle | boolean | true if the form is not in a submission process. |
pending | boolean | true immediately after submission begins, before any delay. |
delayed | boolean | true if the submission is pending longer than delayMs. (Conditional) |
timeout | boolean | true if the submission is pending longer than timeoutMs. (Conditional) |
issues | boolean | true if the submission returned with validation issues. |
error | boolean | true if the submission resulted in an error. |
result | boolean | true if the submission was successful and returned a result. Formerly named success. |
Sources: packages/remotes/src/lib/enhance.svelte.ts:346-365, packages/remotes/CHANGELOG.md:11
Implementing Callbacks
Callbacks are the primary mechanism for executing logic at different points in the submission lifecycle. They are passed as the second argument to the form.enhance() method, which wraps the SvelteKit enhance function.
The sequence diagram below shows how and when each callback is triggered.
Available Callbacks
| Callback | Context | Description |
|---|---|---|
onSubmit | SubmitContext | Called immediately when submission begins. Allows for cancellation or optimistic updates before the request is sent. |
onDelay | BaseEnhanceContext | Called if the submission takes longer than delayMs. Only available if delayMs is set. |
onTimeout | BaseEnhanceContext | Called if the submission takes longer than timeoutMs. Only available if timeoutMs is set. |
onReturn | ... & { result } | Called when the form submission returns successfully with a result. |
onIssues | BaseEnhanceContext | Called when the form submission returns with validation issues. |
onError | ... & { error } | Called when the form submission encounters an error. |
Sources: packages/remotes/src/lib/enhance.svelte.ts:92-138, README.md:84-91
Pre-Submission Control with onSubmit
The onSubmit callback is unique as it provides tools to alter the submission flow before it reaches the server. It receives a context object with cancel() and updates() methods.
| Method | Signature | Description |
|---|---|---|
cancel() | (state?: 'error' | 'issues') => void | Cancels the submission. The form state can optionally be set to error or issues. Defaults to idle. |
updates() | (...queries) => void | Provides queries or overrides for optimistic updates via submit().updates(...). |
This is useful for implementing client-side validation or preparing optimistic UI changes.
<script lang="ts">
// ...
const form = createEnhancedForm(myForm, { validation: valid });
</script>
<form {...myForm.preflight(schema).enhance(opts =>
form.enhance(opts, {
onSubmit: ({ cancel, updates, data }) => {
// Custom client-side checks before submission
if (!customValidationCheck(data)) {
valid.addIssue('fieldName', 'Custom validation failed');
cancel('issues'); // Cancel and set state to 'issues'
return;
}
// Optimistic updates
updates(getPosts().withOverride((posts) => [newPost, ...posts]));
}
})
)}>
<!-- ... -->
</form>
Sources: packages/remotes/src/lib/enhance.svelte.ts:79-85, README.md:93-105, packages/remotes/CHANGELOG.md:8-9
Integration with createValidation
When a validation instance from createValidation is passed to createEnhancedForm, the lifecycle callbacks automatically interact with it to keep validation state synchronized.
The following diagram shows this automated flow.
This integration ensures that validation messages from the server are correctly displayed after a submission with issues, and that a full validation is re-run in case of a submission error.
- On
onIssues:validation.updateIssues()is called to populate the validation store with the issues returned from the server. - On
onError:validation.validateAll()is called to re-validate the entire form against the server.
Sources: packages/remotes/src/lib/enhance.svelte.ts:310-312, packages/remotes/src/lib/enhance.svelte.ts:318-320, packages/remotes/src/lib/validation.svelte.ts:37-41
Conclusion
Using lifecycle callbacks via createEnhancedForm provides a powerful and declarative pattern for managing SvelteKit form submissions. It creates a predictable state machine, simplifies handling of asynchronous operations, and offers hooks for advanced features like optimistic updates and client-side validation. By integrating seamlessly with createValidation, it automates the process of displaying server-side validation feedback, leading to a more robust and user-friendly form experience.
Sources: README.md, packages/remotes/src/lib/enhance.svelte.ts