Repository: sveltejs/kit (JavaScript)

Issue:
`name` and `value` attributes from buttons in forms are not available in `form data` when using `use:enhance`
### Describe the bug

When using the `use:enhance` action on forms, the `name` and `value` attributes provided on buttons are not submitted with the `form data` on form submission and are therefore not available in the `form data` in the action on the server. 

Without using the `use:enhance` action the buttons' `name` and `value` attributes are available in the action on the server.

It does not matter if using the `default` or a named action.

### Example
In this example there is no "button_name":"some_value" key-value pair available in the `form data`.
```javascript
<form method="post" use:enhance>
  <!-- other form elements-->
  <button
    type="submit"
    name="button_name"
    value="some_value">Submit</button
  >
</form>
```

I am not sure if this is intended behavior, I am doing some thing wrong or if this is a bug. 

I have searched through the other issues and discussions but could not find anything related. 

### Reproduction

[Reproduction](https://github.com/philip-weber/sveltekit-form-enhance-no-button-value)

1. Run `npm install`
2. Run `npm run dev`
3. Navigate to [/form-with-enhance](http://localhost:5173/form-with-enhance) and click the submit button.
4. You will see only the name/value from the input field below the form or in the server console.
   ```
   {
     "input_value": "input_form_value"
   }
   ```
5. Navigate to [/form-without-enhance](http://localhost:5173/form-without-enhance) and click the submit button.
6. You will see both the name/value from the input field and the name/value from the button below the form or in the server console.
   ```
   {
     "input_value": "input_form_value",
     "button_value": "submit_button_form_value"
   }
   ```

### Logs

_No response_

### System Info

```shell
System:
    OS: macOS 12.6
    CPU: (4) x64 Intel(R) Core(TM) i5-8210Y CPU @ 1.60GHz
    Memory: 1012.19 MB / 8.00 GB
    Shell: 5.9 - /usr/local/bin/zsh
  Binaries:
    Node: 16.17.1 - ~/.nvm/versions/node/v16.17.1/bin/node
    npm: 8.19.2 - ~/.nvm/versions/node/v16.17.1/bin/npm
  Browsers:
    Chrome: 105.0.5195.125
    Firefox: 105.0.1
    Safari: 16.0
  npmPackages:
    @sveltejs/adapter-auto: next => 1.0.0-next.80
    @sveltejs/kit: next => 1.0.0-next.502
    svelte: ^3.44.0 => 3.50.1
    vite: ^3.1.0 => 3.1.3
```


### Severity

serious, but I can work around it

### Additional Information

Regarding MDN [Element/button#attr-value](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attr-value) a button can have a `value` attribute which should be submitted with the `form data`.

### Workarounds
- For some use cases one can use a hidden field with the value inside the form instead of sending the value with the button
- For other use cases one needs to create multiple forms (with hidden fields) instead of one form with multiple buttons


Discussion:

Patch:
diff --git a/.changeset/sharp-beers-learn.md b/.changeset/sharp-beers-learn.md
new file mode 100644
index 000000000000..77545786a346
--- /dev/null
+++ b/.changeset/sharp-beers-learn.md
@@ -0,0 +1,5 @@
+---
+'@sveltejs/kit': patch
+---
+
+Add the submitter value with name to formData for use:enhance
diff --git a/packages/kit/src/runtime/app/forms.js b/packages/kit/src/runtime/app/forms.js
index f55f3c837c51..738ad9d36931 100644
--- a/packages/kit/src/runtime/app/forms.js
+++ b/packages/kit/src/runtime/app/forms.js
@@ -51,6 +51,12 @@ export function enhance(form, submit = () => {}) {
 		);
 
 		const data = new FormData(form);
+
+		const submitter_name = event.submitter?.getAttribute('name');
+		if (submitter_name) {
+			data.append(submitter_name, event.submitter?.getAttribute('value') ?? '');
+		}
+
 		const controller = new AbortController();
 
 		let cancelled = false;


Test patch:
diff --git a/packages/kit/test/apps/basics/src/routes/actions/enhance/+page.server.js b/packages/kit/test/apps/basics/src/routes/actions/enhance/+page.server.js
index 7a97721c284e..b77d167aefca 100644
--- a/packages/kit/test/apps/basics/src/routes/actions/enhance/+page.server.js
+++ b/packages/kit/test/apps/basics/src/routes/actions/enhance/+page.server.js
@@ -21,5 +21,11 @@ export const actions = {
 	},
 	slow: async () => {
 		await new Promise((resolve) => setTimeout(resolve, 500));
+	},
+	submitter: async ({ request }) => {
+		const fields = await request.formData();
+		return {
+			result: 'submitter: ' + fields.get('submitter')
+		};
 	}
 };
diff --git a/packages/kit/test/apps/basics/src/routes/actions/enhance/+page.svelte b/packages/kit/test/apps/basics/src/routes/actions/enhance/+page.svelte
index 28ddf39f9972..032b7ca9c13b 100644
--- a/packages/kit/test/apps/basics/src/routes/actions/enhance/+page.svelte
+++ b/packages/kit/test/apps/basics/src/routes/actions/enhance/+page.svelte
@@ -17,6 +17,7 @@
 	<input name="username" type="text" />
 	<button class="form1">Submit</button>
 	<button class="form1-register" formAction="?/register">Submit</button>
+	<button class="form1-submitter" formAction="?/submitter" name="submitter" value="foo">Submit</button>
 </form>
 
 <span class="count">{count}</span>
diff --git a/packages/kit/test/apps/basics/test/test.js b/packages/kit/test/apps/basics/test/test.js
index 5d05744984f5..a66e6e1473b3 100644
--- a/packages/kit/test/apps/basics/test/test.js
+++ b/packages/kit/test/apps/basics/test/test.js
@@ -1865,6 +1865,21 @@ test.describe('Actions', () => {
 		);
 	});
 
+	test('use:enhance button with name', async ({ page, app }) => {
+		await page.goto('/actions/enhance');
+
+		expect(await page.textContent('pre.formdata1')).toBe(JSON.stringify(null));
+
+		await Promise.all([
+			page.waitForRequest((request) => request.url().includes('/actions/enhance')),
+			page.click('button.form1-submitter')
+		]);
+
+		await expect(page.locator('pre.formdata1')).toHaveText(
+			JSON.stringify({ result: 'submitter: foo' })
+		);
+	});
+
 	test('redirect', async ({ page }) => {
 		await page.goto('/actions/redirect');