Skip to content

Remote Functions: declarative values for edit forms #15566

Description

@paoloricciuti

Describe the problem

Right now, the API to set values in the form field is imperative, meaning the way to do it is

my_form.fields.set({})
// or
my_form.fields.name.set("My Name")

this makes creating an "edit" form where the values should be initialized with the current values very tricky to do, especially if you want to do it also during SSR to allow for progressive enhancement and especially if you need to have an array of elements. The only somewhat decent solution I found is to create a form.for inside a derived and set the value there

<script>
	import { get_things, add_thing, edit_thing } from './things.remote.ts';
	import { untrack } from "svelte";

	let things = $derived(await get_things());
	let thing_forms = $derived.by(()=>{
		const forms = [];
		for(let thing of things){
			const edit = edit_thing.for(thing.id);
			// we need to untrack because we are setting state in a derived
			// which is a bad practice in svelte
			untrack(()=>{
				edit.fields.set(thing);
			});
			forms.push({
				id: thing.id,
				edit
			});
		}
		return forms;
	});
</script>

this is also currently affected by this bug #15465 which I think we should fix regardless (by removing the check for data already being present...if the user invokes set we should follow that imho especially since the value is not provided by the submission and it's just undefined).

However I think we should have a better API for this by providing the ability to use a value directly in the template taking inspiration by the hidden and submit types.

Describe the proposed solution

Forms fields should accept a second argument, which is the value of the form:

<script>
	import { get_things, add_thing, edit_thing } from './things.remote.ts';
	import { untrack } from "svelte";

	let things = $derived(await get_things());
</script>

{#each things as thing}
	{@const edit_form = edit_thing.for(thing.id)}
	<form {...edit_form}>
		<input {...edit_form.fields.name.as("text", thing.name) />
		<input {...edit_form.fields.age.as("number", thing.age) />
		<button {...edit_form.fields.id.as("submit", thing.id)>Save</button>
	</form>
{/each}

this could also be solved by #14815 if we allow the form factory to receive the initial values.

Alternatives considered

Keep the hack version but fix the submit bug.

Importance

would make my life easier

Additional Information

No response

Activity

  1. henrykrinkle01 commented on Mar 19, 2026

    @henrykrinkle01
    Contributor

    +1
    The only way that makes it bearable and bug-free for me currently is this:

    <script>
    	const {value, ...attrs} = $derived(remote_form.fields.name.as('text');
    	let thing = $derived(await get_thing());
    </script>
    <input {...attrs} value={thing.name} />

    basically skip all the field.set() and field.value() apis

  2. added
    formsStuff relating to forms and form actions
    on Mar 20, 2026
  3. added theissue type on Mar 20, 2026
  4. linked a pull request that will close this issuefeat: remote form factory #14815on Mar 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    formsStuff relating to forms and form actions

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions