Repository navigation
Conversation
radio/array-checkbox inputs now emit a defaultChecked prop mirroring checked, and single-checkbox defaultChecked follows field state instead of the static second argument. the browser reset() fired by the default enhance after a successful same-URL submission therefore restores the current field state rather than first-render defaults, so controls no longer revert and fields.value() stays correct closes sveltejs#16820
|
Install the latest version of pnpm add https://pkg.svelte.dev/@sveltejs/kit/c/3a3dd2680c84cafaddebbad67436a975de5ec485Open in Note This PR is from a fork. A maintainer must approve approve each commit before it can be built and installed. |
🦋 Changeset detectedLatest commit: 3a3dd26 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
Unfortunately. This is incorrect. |
|
Superseded by #16926. Mirroring |
….) and .as('checkbox', ...) (#16926)
Depends on sveltejs/svelte#18701. CI is red because the pinned
svelte@5.56.8 only preserves `defaultChecked` through hydration for
`type="checkbox"`; for radios it strips the SSR `checked` attribute, so
`form.reset()` after a title-only save unchecks the selected radio. The
test asserts the correct behaviour and passes unchanged once #18701 is
released and the catalog is bumped; no kit code or test changes are
needed for that.
Text, select and single-checkbox inputs carry their second .as()
argument into defaultValue/defaultChecked, so the form.reset() the
default enhance runs after a successful submission
(client/remote-functions/form.svelte.js) lands them on the refreshed
current value. Radio and array checkbox inputs (runtime/form-utils.js)
have no such attribute because their second argument is the option
identity, so the reset clears them. Without JS the same happens
server-side where a successful submission is stored without input, so
the re-render has nothing to check.
This PR adds a third argument, the current value of the field:
```svelte
<script>
import { get_settings, update_settings } from './settings.remote';
const settings = $derived(await get_settings());
</script>
<form {...update_settings}>
<input {...update_settings.fields.title.as('text', settings.title)} />
{#each ['public', 'private'] as option}
<label>
<input {...update_settings.fields.visibility.as('radio', option, settings.visibility)} />
{option}
</label>
{/each}
{#each ['red', 'green', 'blue'] as tag}
<label>
<input {...update_settings.fields.tags.as('checkbox', tag, settings.tags)} />
{tag}
</label>
{/each}
<button>Save</button>
</form>
```
defaultChecked is computed from it, and checked from get_value() ??
current_value so the server render after a non-enhanced submission is
right too. Inputs without the third argument keep clearing on reset.
Supersedes #16920.
Fixes #16820
Summary
Closes #16820
After a successful same-URL remote
form()submission, the default enhance resets the element (#14322). Text inputs survived this because.as('text', liveQueryValue)keeps theirdefaultValuein sync with field state, soreset()landed on the persisted value. Radio, checkbox-array and single-checkbox inputs had no equivalent reset-target channel: radio's.assecond argument is the option identity, single-checkboxdefaultCheckedwas a static second argument (usually omitted), so controls snapped back to first-render defaults andfields.value()went stale.Fix (
packages/kit/src/runtime/form-utils.js):defaultChecked, computed by the sameis_checked()closure aschecked— the reset target always mirrors current field statedefaultCheckednow followsget_value() ?? input_value(its existingcheckedcomputation) instead of the static second argumentSince defaults now track state, the post-submit
reset()becomes a visual no-op for these controls andhandle_reset's FormData snapshot re-seedsfields.value()with the correct data — text's existing mechanism, generalized. The public types already declareddefaultCheckedfor checkbox/radio fields, so no type surface changes.Out of scope (flagging explicitly)
selectstill reverts to its first option after the post-submission reset — its default selection lives on<option selected>attributes, which can't be expressed through the<select>element spread. Needs separate design work..as('text', 'constant')) retain their pre-fix behavior — only reactive/live values survive the reset.Testing
packages/kit/test/apps/async/src/routes/remote/form/radio-reset/+ two Playwright cases:fields.value()stays in syncclient.test.js: 92 passed (dev); new tests also pass on the build project; cross-projectform worksincl. no-JS SSR greenpnpm run lint/pnpm run formatclean; changeset included