SvelteKit Remote Functions Workaround Helpers
Source: Dev.to
If you’re like me, you’ve been waiting for Remote Functions in SvelteKit for a long… long time… and they are awesome! Even though they are still experimental, the time they save is priceless. Below is a list of current limitations, workarounds, and their status.
1. Submit Type
You may want to declare your enhance function outside the component template. In form actions you use types like this:
import type { SubmitFunction } from '@sveltejs/kit';
const onSubmit: SubmitFunction = async ({ formElement }) => {
// …
};
There isn’t a direct import for SubmitFunction, so you can derive it:
type SubmitRemoteFunction = Parameters[0];
const onSubmit: SubmitRemoteFunction = async ({ submit }) => {
try {
await submit();
} catch (error) {
console.error(error);
}
};
2. Form Data
formData isn’t passed automatically, but you can derive it:
const onSubmit: SubmitRemoteFunction = async ({ submit, form }) => {
const formData = new FormData(form);
// optional conversion
const data = Object.fromEntries(formData);
// You shouldn’t need this since everything is available
// in the form rune itself, but you never know…
};
3. Set Initial Data
The docs suggest using fields.set, but this isn’t dynamic and can cause a state_referenced_locally error. It also won’t automatically update values on subsequent changes. A fix is to create a helper that re‑initialises the form after hydration:
export function initForm(init: () => void) {
init();
let hydrated = false;
$effect(() => {
if (!hydrated) {
hydrated = true;
return;
}
init();
});
}
Usage
initForm(() =>
updateChapterAccessForm.fields.set({
courseId: initialData.course_id,
chapterId: initialData.id,
isFree: !!initialData.is_free
})
);
4. Form Debug
A small helper component to print the active form data during development (similar to SuperForms but using runes):
import type { RemoteFormFields, RemoteFormInput, RemoteForm } from '@sveltejs/kit';
const { form }: { form: RemoteForm } = $props();
const fields = $derived(form.fields as RemoteFormFields);
{JSON.stringify(
{
values: fields.value(),
issues: fields.allIssues()
},
null,
2
)}
Usage
<!-- Insert component usage here -->
No issue tracker; this is just a development tool.
5. Touched
There’s currently no built‑in touched or pristine state. The following hook tracks whether the whole form has been modified:
import type { RemoteForm, RemoteFormInput } from "@sveltejs/kit";
export const useTouched = (
form: RemoteForm
) => {
const initialValue = JSON.stringify(form.fields.value());
return {
get touched() {
return JSON.stringify(form.fields.value()) !== initialValue;
}
};
};
Usage
const touchForm = useTouched(myForm);
const isSubmitting = $derived(!!myForm.pending);
const isValid = $derived(!myForm.fields.allIssues() && touchForm.touched);
// touchForm.touched
That’s all for now. Feel free to share any additional workarounds you discover!