Skip to content

fix: don't reset <select> elements to the first option after a remote form submission#16107

Draft
RazinShafayet2007 wants to merge 9 commits into
sveltejs:mainfrom
RazinShafayet2007:fix/select-reset-on-submit
Draft

fix: don't reset <select> elements to the first option after a remote form submission#16107
RazinShafayet2007 wants to merge 9 commits into
sveltejs:mainfrom
RazinShafayet2007:fix/select-reset-on-submit

Conversation

@RazinShafayet2007

@RazinShafayet2007 RazinShafayet2007 commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

Fixes #16093

After a successful remote-form submission, the framework called native form.reset() to clear the form. For <select> elements, native reset restores whichever <option> has the selected attribute, or falls back to the first option if none does — and since most <select> markup doesn't declare an explicit default, every successful submission caused the select to snap back to its first option, discarding what the user actually picked.

This PR replaces that reset call with read_default_values(), which resolves each field to its correct post-submit state explicitly rather than delegating to the browser. Text inputs, checkboxes, radios, and textareas keep the same behavior as before (defaultValue/defaultChecked). For <select>, a genuine, non-disabled declared default is restored just like defaultValue on a text input, while a select with no usable default — none declared, or only a disabled placeholder like <option selected disabled> — preserves the submitted value instead, captured at submit time to avoid a race condition with the DOM. The same logic applies to multi-select. Tests cover all four resulting behaviors, including multi-select restoring every declared default.


Please don't delete this checklist! Before submitting the PR, please make sure you do the following:

  • It's really useful if your PR references an issue where it is discussed ahead of time. In many cases, features are absent for a reason. For large changes, please create an RFC: https://github.com/sveltejs/rfcs
  • This message body should clearly illustrate what problems it solves.
  • Ideally, include a test that fails without this PR but passes with it.

Tests

  • Run the tests with pnpm test and lint the project with pnpm lint and pnpm check

Changesets

  • If your PR makes a change that should be noted in one or more packages' changelogs, generate a changeset by running pnpm changeset and following the prompts. Changesets that add features should be minor and those that fix bugs should be patch. Please prefix changeset messages with feat:, fix:, or chore:.

Edits

  • Please ensure that 'Allow edits from maintainers' is checked. PRs without this option may be closed.

@changeset-bot

changeset-bot Bot commented Jun 20, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 5cc79d5

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@sveltejs/kit Patch

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

if (select.multiple) {
if (default_options.length > 0) {
for (const opt of default_options) fd.append(name, opt.value);
} else if (submitted_data && submitted_data[name] !== undefined) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In read_default_values, the captured submitted value is looked up with the raw DOM element name, but submitted_data keys were normalized by convert_formdata (stripped n:/b: prefix and [] suffix, nested paths), so the lookup always misses for prefixed/suffixed/nested select names and falls back to the stale DOM.

Fix on Vercel

@RazinShafayet2007 RazinShafayet2007 marked this pull request as draft June 20, 2026 15:55
@RazinShafayet2007 RazinShafayet2007 force-pushed the fix/select-reset-on-submit branch from 9f463c8 to 8e9b2eb Compare June 20, 2026 16:20
@ottomated

ottomated commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

This is pretty complicated for what should just be defaultValue on <select> elements. .as('select', 'value') can't set selected on the child option because it's just spread onto the parent <select>. Maybe requires a change in svelte to add defaultValue to <select>s?

(also, this PR won't work for when form.reset() is called outside of submission and the tests should be consolidated)

@RazinShafayet2007

Copy link
Copy Markdown
Contributor Author

@ottomated You were right, there was a real gap in form.reset() thing. To fix that, added e.preventDefault() in handle_reset and pointed it at the same read_default_values() helper the submit path already uses, just with undefined instead of the submitted data, since there's nothing to fall back to on a manual reset. So hitting a reset button (or calling .reset() from anywhere) won't trigger native reset's broken select behavior anymore either. Threw in a test that clicks an actual <button type="reset"> so this doesn't quietly break later.

I agree it's not the prettiest but the complexity comes from working around the DOM's limits, <select> has no defaultValue. The defaultSelected && !disabled heuristic mirrors what defaultValue/defaultChecked do for other elements, just expressed through child options since that's the only API available. Although I'd grant that a Svelte-level defaultValue on <select> would make this cleaner.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

select elements change to first option on submit

2 participants