Optimistic UI with `updates()`
Relevant source files
The following files were used as context for generating this wiki page:The @opensky/remotes package provides a powerful mechanism for implementing optimistic UI updates in SvelteKit applications through the createEnhancedForm helper. This feature, centered around the updates() function, allows developers to immediately reflect anticipated server-side changes in the user interface upon form submission, without waiting for the server's response. This creates a faster, more responsive user experience.
The updates() function is exposed within the onSubmit callback of the enhanced form. It works by accepting SvelteKit RemoteQuery or RemoteQueryOverride objects, which define how client-side data caches should be temporarily modified. This functionality was added in version 0.0.3 of the package.
Sources: packages/remotes/README.md:89-102, packages/remotes/CHANGELOG.md:5-7, packages/remotes/src/lib/enhance.svelte.ts:83-86
Core Concepts
Optimistic updates are managed within the lifecycle of createEnhancedForm. The key is the onSubmit callback, which intercepts the form submission before it's sent to the server. This callback receives a SubmitContext object containing the tools needed to manage the submission, including the updates() function.
Sources: packages/remotes/src/lib/enhance.svelte.ts:90-92, packages/remotes/README.md:93-102
The SubmitContext Object
When the enhance method from createEnhancedForm is invoked, the onSubmit callback receives a SubmitContext object. This object provides control over the submission flow.
The diagram below illustrates the structure of the SubmitContext object.
The properties of the SubmitContext are detailed in the table below.
| Property | Type | Description |
|---|---|---|
form | HTMLFormElement | The HTML form element being submitted. |
submit | () => Promise<void> | The function to call to proceed with the actual form submission. |
data | TData | The form data being submitted. |
remote | RemoteForm<any, TResult> | The SvelteKit RemoteForm instance. |
cancel | (state?: 'error' | 'issues') => void | A function to cancel the submission. If called, submit() is not executed. |
updates | (...queries: Array<RemoteQuery<any> | RemoteQueryOverride>) => void | A function to provide queries/overrides for optimistic updates. |
Sources: packages/remotes/src/lib/enhance.svelte.ts:10-16, packages/remotes/src/lib/enhance.svelte.ts:77-86
The updates() Function
The updates() function is the core of the optimistic UI feature. It is called within the onSubmit callback before the actual submit() function is invoked. It accepts one or more SvelteKit RemoteQuery or RemoteQueryOverride objects. These objects tell SvelteKit how to temporarily modify the data of a given query, which immediately updates any components that depend on that data.
// packages/remotes/src/lib/enhance.svelte.ts:278-282
// Call submit with or without updates
if (updateQueries.length > 0) {
await params.submit().updates(...updateQueries)
} else {
await params.submit()
}
The enhanceHandler stores the provided queries in an updateQueries array and then passes them to SvelteKit's native submit().updates() method.
Sources: packages/remotes/src/lib/enhance.svelte.ts:265, packages/remotes/src/lib/enhance.svelte.ts:278-282, packages/remotes/README.md:99-102
Implementation Flow
The following sequence diagram illustrates the entire process, from a user submitting a form to the UI being optimistically updated.
This diagram shows how the EnhancedForm handler intercepts the submission, allows the developer to apply optimistic updates, and then proceeds with the actual submission, while SvelteKit handles the UI changes and eventual consistency.
Sources: packages/remotes/src/lib/enhance.svelte.ts:258-308
Combining with Client-Side Validation
The onSubmit callback can also be used for client-side validation before attempting an optimistic update or server submission. The cancel() function, provided in the SubmitContext, can be used to halt the submission process entirely. This is useful when combined with the createValidation helper to add custom validation errors.
The flow is as follows:
- Perform a custom validation check inside
onSubmit. - If validation fails, use
validation.addIssue()to register an error. - Call
cancel('issues')to stop the submission and set the form state to'issues'. - If validation passes, proceed with calling
updates()andsubmit().
Sources: packages/remotes/README.md:95-98, packages/remotes/src/lib/validation.svelte.ts:111-120, packages/remotes/src/lib/enhance.svelte.ts:268-272
This logic is visualized in the following flowchart:
Practical Example
Here is a practical example of using updates() for an optimistic UI when adding a new post.
<script lang="ts">
import { createValidation, createEnhancedForm } from '@opensky/remotes';
import { getPosts, myForm } from './remotes'; // Fictional remotes
import { z } from 'zod';
const schema = z.object({
// ... schema definition
});
const valid = createValidation(myForm);
const form = createEnhancedForm(myForm, { validation: valid });
// Assume newPost is created from form data
let newPost = { id: 'temp-id', title: 'My New Post' };
</script>
<form {...myForm.preflight(schema).enhance(opts =>
form.enhance(opts, {
onSubmit: ({ cancel, updates, data }) => {
// Optimistic updates
updates(getPosts().withOverride((posts) => [newPost, ...posts]))
},
onReturn: ({ result }) => {
console.log('Post successfully created!', result);
},
onError: ({ error }) => {
console.error('Failed to create post:', error);
// SvelteKit will automatically revert the optimistic update
}
})
)}>
<!-- form fields -->
<button disabled={form.pending}>Submit</button>
</form>
In this example, when the form is submitted, the updates() function is called with an override for the getPosts query. It prepends the newPost object to the local cache of posts, causing the UI to instantly display the new post. The form then proceeds to submit to the server. If the server returns an error, SvelteKit automatically reverts the optimistic change.
Sources: packages/remotes/README.md:93-102, packages/remotes/src/lib/index.ts
Conclusion
The updates() function, as part of the createEnhancedForm helper, provides a clean and powerful API for implementing optimistic UI updates with SvelteKit's remote forms. By intercepting form submissions and providing temporary data overrides, it allows developers to build highly responsive and fluid user interfaces that feel instantaneous to the user, significantly improving the perceived performance of the application.
Sources: packages/remotes/README.md:65-71, packages/remotes/src/lib/enhance.svelte.ts:210-215