From 30c24e67cffec3488f9d113849ed9375f077a610 Mon Sep 17 00:00:00 2001 From: cofl Date: Sat, 11 Oct 2025 15:47:03 +0000 Subject: [PATCH 1/3] Allow boolean and number form fields to be hidden --- packages/kit/src/exports/public.d.ts | 8 ++++- packages/kit/src/runtime/form-utils.svelte.js | 32 +++++++++++++++++-- packages/kit/types/index.d.ts | 8 ++++- 3 files changed, 43 insertions(+), 5 deletions(-) diff --git a/packages/kit/src/exports/public.d.ts b/packages/kit/src/exports/public.d.ts index 01e4f8cf9eb9..bfa944cd2b7d 100644 --- a/packages/kit/src/exports/public.d.ts +++ b/packages/kit/src/exports/public.d.ts @@ -1833,6 +1833,8 @@ type InputTypeMap = { radio: string; file: File; hidden: string; + 'hidden boolean': boolean; + 'hidden number': number; submit: string; button: string; reset: string; @@ -1890,7 +1892,11 @@ type AsArgs = Type extends 'checkbox' : [type: Type] : Type extends 'radio' | 'submit' | 'hidden' ? [type: Type, value: Value | (string & {})] - : [type: Type]; + : Type extends 'hidden number' + ? [type: Type, value: Value | (number & {})] + : Type extends 'hidden boolean' + ? [type: Type, value: Value | (boolean & {})] + : [type: Type]; /** * Form field accessor type that provides name(), value(), and issues() methods diff --git a/packages/kit/src/runtime/form-utils.svelte.js b/packages/kit/src/runtime/form-utils.svelte.js index 4d0ff75d7318..fe44e598c6af 100644 --- a/packages/kit/src/runtime/form-utils.svelte.js +++ b/packages/kit/src/runtime/form-utils.svelte.js @@ -249,7 +249,7 @@ export function create_field_proxy(target, get_input, depend, set_input, get_iss if (prop === 'as') { /** * @param {string} type - * @param {string} [input_value] + * @param {string | number | boolean} [input_value] */ const as_func = (type, input_value) => { const is_array = @@ -258,9 +258,9 @@ export function create_field_proxy(target, get_input, depend, set_input, get_iss (type === 'checkbox' && typeof input_value === 'string'); const prefix = - type === 'number' || type === 'range' + type === 'number' || type === 'range' || type === 'hidden number' ? 'n:' - : type === 'checkbox' && !is_array + : (type === 'checkbox' && !is_array) || type === 'hidden boolean' ? 'b:' : ''; @@ -292,6 +292,32 @@ export function create_field_proxy(target, get_input, depend, set_input, get_iss }); } + // Handle hidden number inputs + if (type === 'hidden number') { + if (DEV) { + if (typeof input_value !== 'number') { + throw new Error(`\`hidden number\` input must be a number value.`); + } + } + + return Object.defineProperties(base_props, { + value: { value: input_value, enumerable: true } + }); + } + + // Handle hidden boolean inputs + if (type === 'hidden boolean') { + if (DEV) { + if (typeof input_value !== 'boolean') { + throw new Error(`\`hidden boolean\` input must be a boolean value.`); + } + } + + return Object.defineProperties(base_props, { + value: { value: input_value && 'on', enumerable: true } + }); + } + // Handle select inputs if (type === 'select' || type === 'select multiple') { return Object.defineProperties(base_props, { diff --git a/packages/kit/types/index.d.ts b/packages/kit/types/index.d.ts index b503853794e8..209ac3457d3b 100644 --- a/packages/kit/types/index.d.ts +++ b/packages/kit/types/index.d.ts @@ -1809,6 +1809,8 @@ declare module '@sveltejs/kit' { radio: string; file: File; hidden: string; + 'hidden boolean': boolean; + 'hidden number': number; submit: string; button: string; reset: string; @@ -1866,7 +1868,11 @@ declare module '@sveltejs/kit' { : [type: Type] : Type extends 'radio' | 'submit' | 'hidden' ? [type: Type, value: Value | (string & {})] - : [type: Type]; + : Type extends 'hidden number' + ? [type: Type, value: Value | (number & {})] + : Type extends 'hidden boolean' + ? [type: Type, value: Value | (boolean & {})] + : [type: Type]; /** * Form field accessor type that provides name(), value(), and issues() methods From 9923907463b967457f69b971a6dbf0784ddd8dfb Mon Sep 17 00:00:00 2001 From: cofl Date: Sat, 11 Oct 2025 12:42:05 +0000 Subject: [PATCH 2/3] Add tests for hidden form field types --- .../routes/remote/form/hidden/+page.svelte | 18 ++++++++++++++ .../routes/remote/form/hidden/form.remote.ts | 24 +++++++++++++++++++ packages/kit/test/apps/basics/test/test.js | 14 +++++++++++ 3 files changed, 56 insertions(+) create mode 100644 packages/kit/test/apps/basics/src/routes/remote/form/hidden/+page.svelte create mode 100644 packages/kit/test/apps/basics/src/routes/remote/form/hidden/form.remote.ts diff --git a/packages/kit/test/apps/basics/src/routes/remote/form/hidden/+page.svelte b/packages/kit/test/apps/basics/src/routes/remote/form/hidden/+page.svelte new file mode 100644 index 000000000000..d706ed556ea8 --- /dev/null +++ b/packages/kit/test/apps/basics/src/routes/remote/form/hidden/+page.svelte @@ -0,0 +1,18 @@ + + + +{#await hidden then h} +

await hidden().string: {h.string}

+

await hidden().number: {h.number}

+

await hidden().boolean: {h.boolean}

+{/await} + +
+ + + + +
diff --git a/packages/kit/test/apps/basics/src/routes/remote/form/hidden/form.remote.ts b/packages/kit/test/apps/basics/src/routes/remote/form/hidden/form.remote.ts new file mode 100644 index 000000000000..c686e65bb4d1 --- /dev/null +++ b/packages/kit/test/apps/basics/src/routes/remote/form/hidden/form.remote.ts @@ -0,0 +1,24 @@ +import { form, query } from '$app/server'; +import * as v from 'valibot'; + +let hidden = { + string: 'a', + number: 0, + boolean: false +}; + +export const get_hidden = query(() => { + return hidden; +}); + +export const set_hidden = form( + v.object({ + string: v.string(), + number: v.number(), + boolean: v.boolean() + }), + async (data) => { + hidden = data; + get_hidden().refresh(); + } +); diff --git a/packages/kit/test/apps/basics/test/test.js b/packages/kit/test/apps/basics/test/test.js index 1e64ded04982..babc4b712d24 100644 --- a/packages/kit/test/apps/basics/test/test.js +++ b/packages/kit/test/apps/basics/test/test.js @@ -1693,6 +1693,20 @@ test.describe('remote functions', () => { await expect(page.locator('#result')).toHaveText('hello'); }); + test('form hidden inputs of different types work', async ({ page, javaScriptEnabled }) => { + await page.goto('/remote/form/hidden'); + + await page.locator('button').click(); + + if (javaScriptEnabled) { + await expect(page.getByText('await hidden().string:')).toHaveText('await hidden().string: b'); + await expect(page.getByText('await hidden().number:')).toHaveText('await hidden().number: 1'); + await expect(page.getByText('await hidden().boolean:')).toHaveText( + 'await hidden().boolean: true' + ); + } + }); + test('form updates inputs live', async ({ page, javaScriptEnabled }) => { await page.goto('/remote/form'); From ebd63b200b0cd9ab6f5fb56cc8de2326fe21fbc1 Mon Sep 17 00:00:00 2001 From: cofl Date: Sun, 12 Oct 2025 20:38:37 +0000 Subject: [PATCH 3/3] Add changeset --- .changeset/poor-yaks-warn.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/poor-yaks-warn.md diff --git a/.changeset/poor-yaks-warn.md b/.changeset/poor-yaks-warn.md new file mode 100644 index 000000000000..10007ae2821f --- /dev/null +++ b/.changeset/poor-yaks-warn.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/kit': minor +--- + +feat: Add "hidden number" and "hidden boolean" input types for remote form fields