Skip to content

feat: callable forms#15986

Open
Rich-Harris wants to merge 4 commits into
mainfrom
callable-forms
Open

feat: callable forms#15986
Rich-Harris wants to merge 4 commits into
mainfrom
callable-forms

Conversation

@Rich-Harris

Copy link
Copy Markdown
Member

I found myself wanting to call a form directly, without actually using it on a <form>. In my case specifically it was for a recursive operation — I wanted the user to invoke deleteFile as a traditional <form>, but inside the handler I wanted to be able to call deleteFile as a function, which is currently impossible:

image

Obviously you can work around this by yoinking the logic out into a separate function, but it's not as nice — it's less self-contained, and you need to come up with two names instead of one. I gather I'm not the only person who has encountered cases like this.

The implementation is pleasingly simple — we just call command under the hood, remove the is_form_content_type check and it basically Just Works AFAICT? There is one change: myform.pending needs to become myform.submitting so that we can distinguish between form submissions (myform.submitting) and direct calls (myform.pending).

Note that the semantics of direct calls are exactly the same as for command:

  • things like myform.fields.foo.issues() and myform.result do not get populated — these only happen for form submissions
  • form submissions invalidate everything on the page by default (we still need to come up with a sensible API for preventing this within the form handler...), whereas direct calls do not

Of course, the obvious follow-up question: if we can do this, is there any point in keeping command around? Two possible arguments:

  • if you only use command in your app and not form, you will have a very slightly smaller JS bundle
  • command can have any schema, whereas form always has to be a v.object({...}) or the non-Valibot equivalent

I'm personally not sure those are compelling enough reasons, but this is a conversation to have as a follow-up.


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 8, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: a3640d1

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

Rich-Harris and others added 2 commits June 8, 2026 13:15
Updated the changeset to reflect breaking changes in form properties.
@phi-bre

phi-bre commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

I've found myself wishing for this feature but not to replace commands but rather because only form properly handles streaming of file uploads. Using command under the hood in combination with #15978 will buffer the whole file for its JSON body.

I can open a new issue for that tho (I'm aware this addition is non-trivial, devalue does not support streaming, and the form uploads use a custom protocol afaik)

@Rich-Harris

Copy link
Copy Markdown
Member Author

Yeah, would love to be able to do that. Mostly we just haven't figured out a good use-case-agnostic API for devalue to deal with async/streaming values (but then again we haven't spent a lot of time thinking about it)

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.

2 participants