Skip to content

feat: programmatic form submissions#15657

Merged
teemingc merged 15 commits into
mainfrom
programmatic-submit
May 18, 2026
Merged

feat: programmatic form submissions#15657
teemingc merged 15 commits into
mainfrom
programmatic-submit

Conversation

@Rich-Harris

Copy link
Copy Markdown
Member

This implements #14082 (comment):

  • Remote form instances have a programmatic submit() method (await myform.submit())
  • This runs preflight checks, then submits the contents of the form (using the default submitter). It does not run logic inside an enhance callback
  • It returns a Promise with an updates method that can be used for optimistic updates
  • Enhance callbacks now receive a copy of the instance, rather than a { form, data, submit } object. (It's a copy because we don't want people to just call instance.submit() inside the enhance callback, since that would result in preflight validation running twice)

To facilitate this I made a small change to the implementation — instead of enhance(...) returning a fresh object, it just stashes away the callback for later. This is simpler and more consistent with how preflight works — it means you can do this, for example, without having to stash away a reference in order to spread it:

<script>
  import { myform } from './stuff.remote';

  myform.preflight(schema).enhance(async (f) => {
    // ...
  });
</script>

<form {...myform}>...</form>

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 Apr 5, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 9a41c75

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 Minor

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

@svelte-docs-bot

Copy link
Copy Markdown

Comment thread packages/kit/src/runtime/client/remote-functions/form.svelte.js Outdated
Comment thread packages/kit/src/runtime/client/remote-functions/form.svelte.js Outdated
Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com>
@teemingc teemingc added the forms Stuff relating to forms and form actions label Apr 6, 2026
@Rich-Harris Rich-Harris mentioned this pull request Apr 8, 2026
Comment thread .changeset/salty-doors-feel.md Outdated
Comment thread .changeset/sweet-lamps-invite.md Outdated
@coeternity7

coeternity7 commented May 8, 2026

Copy link
Copy Markdown

Hi! Is it a correct assessment that these changes would allow submission of forms without a dedicated type="submit" button? I had an issue that I was about to submit about said use case before finding this PR (oops).

Separately, in scenarios where you have multiple instances of a form using the pattern described here, can each instance of the form with its respective separate id property be differentiated between to be programmatically submitted separately of one another? If that in itself is enough of a problem or use case that warrants its own issue I could still submit one describing it.

Thank you for the work on SvelteKit.

@teemingc

Copy link
Copy Markdown
Member

Hi! Is it a correct assessment that these changes would allow submission of forms without a dedicated type="submit" button? I had an issue that I was about to submit about said use case before finding this PR (oops).

Yes, but it's still a good practice to have one. I'm curious as to why your form wouldn't have one.

Separately, in scenarios where you have multiple instances of a form using the pattern described here, can each instance of the form with its respective separate id property be differentiated between to be programmatically submitted separately of one another? If that in itself is enough of a problem or use case that warrants its own issue I could still submit one describing it.

Yes, you would simply access .submit() from each different form instance.

@teemingc teemingc merged commit f294e96 into main May 18, 2026
25 of 26 checks passed
@teemingc teemingc deleted the programmatic-submit branch May 18, 2026 21:49
This was referenced May 18, 2026
@ottomated ottomated mentioned this pull request May 20, 2026
6 tasks
Rich-Harris pushed a commit that referenced this pull request May 22, 2026
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @sveltejs/kit@2.61.0

### Minor Changes

- breaking: the `.run()` method has been removed from remote queries on
both the client and the server. Use `await query()` directly instead —
it now works everywhere
([#15779](#15779))


- feat: remote queries can now be awaited in any context (event
handlers, module scope, async callbacks), not just inside reactive
contexts. The cache is shared across reactive and non-reactive
subscribers, so awaiting a query in an event handler will dedupe with
components that have already subscribed to the same query.
([#15779](#15779))


- feat: live query instances are now themselves async-iterable
([#15878](#15878))


- feat: add programmatic `submit` method to `form` remote function
instances ([#15657](#15657))


- feat: pass `form` remote function instance into `enhance` callback
([#15657](#15657))

### Patch Changes

- fix: resolve the app payload without using `process.env.NODE_ENV`
([#15852](#15852))


- fix: support `exactOptionalPropertyTypes` for optional route params
([#15825](#15825))


- fix: correctly send `true` value to the server for 'submit' and
'hidden' form fields
([#15858](#15858))


- fix: avoid build warnings about undefined universal hooks
([#15895](#15895))


- fix: prefer default error page when failing to decode the URL pathname
([#15744](#15744))


- fix: disable link prefetching on slow internet connections
([#15885](#15885))


- fix: allow routes ending with optional parameters next to more
specific routes ([#15861](#15861))


- fix: remove reliance on Content-Length header in
deserialize_binary_form, which caused failures when proxies (e.g.
Vercel, Azure) strip the header and use chunked transfer encoding
([#15796](#15796))

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
ollema added a commit to ollema/skiftesgatan.se that referenced this pull request May 26, 2026
## Summary
- Bumps deps (commit c861d37).
- Adapts the codebase to API changes that landed in SvelteKit 2.61:
- **RemoteForm enhance callback**
([kit#15657](sveltejs/kit#15657)): the callback
now receives the form instance directly. The old `form` field on the
callback arg is gone; the underlying `HTMLFormElement` is now `element`.
Migrated `konto/+page.svelte` (changeName, changeEmail, changePassword)
and `admin/[username]/+page.svelte` (updateUserName, updateUserEmail).
- **Calendar prop drop**: bits-ui's Calendar no longer accepts the
`slotCount` prop. Removed the unused derived value and prop pass in
`BookingPage.svelte`.

Other SvelteKit changes reviewed but no code changes needed here:
- [kit#15779](sveltejs/kit#15779) (isomorphic
query caching, `.run` removal): we don't call `.run` anywhere.
- [kit#15878](sveltejs/kit#15878) (LiveQuery
self-iterability): additive; existing `await live` pattern still works.
- [kit#15802](sveltejs/kit#15802) (hidden/submit
accept numbers/booleans): no `as('hidden'|'submit')` call sites today.
- [kit#15653](sveltejs/kit#15653) (warn on
unread validation issues): every form already renders
`fields.allIssues()`.

## Test plan
- [x] `pnpm check` — 0 errors / 0 warnings
- [x] `pnpm test` — 55 unit tests passed, 36 e2e tests passed
@Stadly

Stadly commented May 28, 2026

Copy link
Copy Markdown
Contributor

Now that data is no longer available in the enhance callback, is form.fields.value() the right way to get it?

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

Labels

forms Stuff relating to forms and form actions

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Remote Functions: Return form response when calling submit in enhance

4 participants