Skip to content

Commit 82581e7

Browse files
committed
Fix missing form data when the submitter is outside the form
Fixes #27391 `form-associated elements` can be associated with `<form>`s anywhere in the document (even if the element is outside the `<form>`), and as with any submitter, the `name` and `value` are expected to be reflected in the final `FormData`.
1 parent 190cc99 commit 82581e7

File tree

2 files changed

+27
-7
lines changed

2 files changed

+27
-7
lines changed

packages/react-dom-bindings/src/events/plugins/FormActionEventPlugin.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,10 @@ function extractEvents(
9292
const temp = submitter.ownerDocument.createElement('input');
9393
temp.name = submitter.name;
9494
temp.value = submitter.value;
95+
const isOutsideForm = !form.contains(submitter);
96+
if (isOutsideForm) {
97+
temp.setAttribute('form', form.id);
98+
}
9599
(submitter.parentNode: any).insertBefore(temp, submitter);
96100
formData = new FormData(form);
97101
(temp.parentNode: any).removeChild(temp);

packages/react-dom/src/__tests__/ReactDOMForm-test.js

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,7 @@ describe('ReactDOMForm', () => {
481481
it('can read the clicked button in the formdata event', async () => {
482482
const inputRef = React.createRef();
483483
const buttonRef = React.createRef();
484+
const outsideButtonRef = React.createRef();
484485
let button;
485486
let title;
486487

@@ -492,14 +493,24 @@ describe('ReactDOMForm', () => {
492493
const root = ReactDOMClient.createRoot(container);
493494
await act(async () => {
494495
root.render(
495-
<form action={action}>
496-
<input type="text" name="title" defaultValue="hello" />
497-
<input type="submit" name="button" value="save" />
498-
<input type="submit" name="button" value="delete" ref={inputRef} />
499-
<button name="button" value="edit" ref={buttonRef}>
500-
Edit
496+
<>
497+
<button
498+
form="form"
499+
name="button"
500+
value="outside"
501+
ref={outsideButtonRef}>
502+
Edit from outside
501503
</button>
502-
</form>,
504+
<form id="form" action={action}>
505+
<input type="text" name="title" defaultValue="hello" />
506+
<input type="submit" name="button" value="save" />
507+
<input type="submit" name="button" value="delete" ref={inputRef} />
508+
<button name="button" value="edit" ref={buttonRef}>
509+
Edit
510+
</button>
511+
</form>
512+
,
513+
</>,
503514
);
504515
});
505516

@@ -520,6 +531,11 @@ describe('ReactDOMForm', () => {
520531
expect(button).toBe('edit');
521532
expect(title).toBe('hello');
522533

534+
await submit(outsideButtonRef.current);
535+
536+
expect(button).toBe('outside');
537+
expect(title).toBe('hello');
538+
523539
// Ensure that the type field got correctly restored
524540
expect(inputRef.current.getAttribute('type')).toBe('submit');
525541
expect(buttonRef.current.getAttribute('type')).toBe(null);

0 commit comments

Comments
 (0)