diff --git a/.changeset/full-steaks-count.md b/.changeset/full-steaks-count.md new file mode 100644 index 000000000000..df4c781b47fa --- /dev/null +++ b/.changeset/full-steaks-count.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/kit': minor +--- + +feat: reset form programmatically diff --git a/documentation/docs/20-core-concepts/60-remote-functions.md b/documentation/docs/20-core-concepts/60-remote-functions.md index 969b90d17121..aaa72faea9d5 100644 --- a/documentation/docs/20-core-concepts/60-remote-functions.md +++ b/documentation/docs/20-core-concepts/60-remote-functions.md @@ -847,6 +847,46 @@ This attribute exists on the `buttonProps` property of a form object: Like the form object itself, `buttonProps` has an `enhance` method for customizing submission behaviour. +### Resetting the form programmatically + +You can programmatically reset a form using the `reset()` method. When called with no arguments, `reset()` will: + +- Reset the HTML form element (clearing all input values) +- Clear all validation issues +- Clear the `result` value +- Clear all touched field tracking +- Set `submitted` to `false` + +```svelte + + + +
+ + +``` + +The available options are: + +- `values` — Set to `true` (default) to reset the HTML form element, `false` to keep current values, or pass an object with partial values to reset to specific values +- `issues` — Set to `false` to preserve validation issues (default is `true`) +- `result` — Set to `false` to preserve the result value (default is `true`) +- `touched` — Set to `false` to preserve touched field tracking (default is `true`) + +```svelte + +``` + ## command The `command` function, like `form`, allows you to write data to the server. Unlike `form`, it's not specific to an element and can be called from anywhere. diff --git a/packages/kit/src/exports/public.d.ts b/packages/kit/src/exports/public.d.ts index cb42dc6cc1c0..840eddaed7ed 100644 --- a/packages/kit/src/exports/public.d.ts +++ b/packages/kit/src/exports/public.d.ts @@ -5,6 +5,7 @@ import '../types/ambient.js'; import { AdapterEntry, CspDirectives, + DeepPartial, HttpMethod, Logger, MaybePromise, @@ -2052,6 +2053,21 @@ export type RemoteForm = { /** Perform validation as if the form was submitted by the given button. */ submitter?: HTMLButtonElement | HTMLInputElement; }): Promise{JSON.stringify(test.result)}
+{JSON.stringify(test.fields.value.value())}
+{JSON.stringify(test.fields.allIssues())}
diff --git a/packages/kit/test/apps/basics/src/routes/remote/form/reset/form.remote.ts b/packages/kit/test/apps/basics/src/routes/remote/form/reset/form.remote.ts
new file mode 100644
index 000000000000..fbf5f9b050ff
--- /dev/null
+++ b/packages/kit/test/apps/basics/src/routes/remote/form/reset/form.remote.ts
@@ -0,0 +1,12 @@
+import { form } from '$app/server';
+import * as v from 'valibot';
+
+export const test = form(
+ v.object({
+ value: v.pipe(v.string(), v.minLength(3))
+ }),
+ async (data) => {
+ console.log(data);
+ return data;
+ }
+);
diff --git a/packages/kit/test/apps/basics/test/test.js b/packages/kit/test/apps/basics/test/test.js
index 9b57a59b79d7..62c44c3045a6 100644
--- a/packages/kit/test/apps/basics/test/test.js
+++ b/packages/kit/test/apps/basics/test/test.js
@@ -2018,6 +2018,46 @@ test.describe('remote functions', () => {
await page.fill('input', 'hello');
await expect(page.locator('select')).toHaveValue('one');
});
+
+ test('form resets programmatically', async ({ page, javaScriptEnabled }) => {
+ await page.goto('/remote/form/reset');
+
+ // SSR case
+ await expect(page.locator('#value')).toHaveText('"hi"');
+
+ if (!javaScriptEnabled) return;
+
+ // Error case
+ await page.locator('#submit').click();
+ await expect(page.locator('#value')).toHaveText('"hi"');
+ await expect(page.locator('#result')).toHaveText('');
+ await expect(page.locator('#allIssues')).toHaveText(
+ '[{"message":"Invalid length: Expected >=3 but received 2"}]'
+ );
+
+ await page.locator('#partial-reset').click();
+ await expect(page.locator('#value')).toHaveText('""');
+ await expect(page.locator('#allIssues')).toHaveText(
+ '[{"message":"Invalid length: Expected >=3 but received 2"}]'
+ );
+
+ await page.locator('#full-reset').click();
+ await expect(page.locator('#allIssues')).toHaveText('');
+
+ // Result case
+ await page.locator('#input').fill('hello');
+ await page.locator('#submit').click();
+ await expect(page.locator('#value')).toHaveText('"hello"');
+ await expect(page.locator('#result')).toHaveText('{"value":"hello"}');
+ await expect(page.locator('#allIssues')).toHaveText('');
+
+ await page.locator('#partial-reset').click();
+ await expect(page.locator('#value')).toHaveText('""');
+ await expect(page.locator('#result')).toHaveText('{"value":"hello"}');
+
+ await page.locator('#full-reset').click();
+ await expect(page.locator('#result')).toHaveText('');
+ });
});
test.describe('params prop', () => {
diff --git a/packages/kit/types/index.d.ts b/packages/kit/types/index.d.ts
index 9fde95c8dd4c..f4f9d1f2b862 100644
--- a/packages/kit/types/index.d.ts
+++ b/packages/kit/types/index.d.ts
@@ -2028,6 +2028,21 @@ declare module '@sveltejs/kit' {
/** Perform validation as if the form was submitted by the given button. */
submitter?: HTMLButtonElement | HTMLInputElement;
}): Promise