Skip to content

Commit 1933c2c

Browse files
committed
Fix missing form data when the submitter is outside the form
Fixes facebook#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 2f803b4 commit 1933c2c

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
@@ -483,6 +483,7 @@ describe('ReactDOMForm', () => {
483483
it('can read the clicked button in the formdata event', async () => {
484484
const inputRef = React.createRef();
485485
const buttonRef = React.createRef();
486+
const outsideButtonRef = React.createRef();
486487
let button;
487488
let title;
488489

@@ -494,14 +495,24 @@ describe('ReactDOMForm', () => {
494495
const root = ReactDOMClient.createRoot(container);
495496
await act(async () => {
496497
root.render(
497-
<form action={action}>
498-
<input type="text" name="title" defaultValue="hello" />
499-
<input type="submit" name="button" value="save" />
500-
<input type="submit" name="button" value="delete" ref={inputRef} />
501-
<button name="button" value="edit" ref={buttonRef}>
502-
Edit
498+
<>
499+
<button
500+
form="form"
501+
name="button"
502+
value="outside"
503+
ref={outsideButtonRef}>
504+
Edit from outside
503505
</button>
504-
</form>,
506+
<form id="form" action={action}>
507+
<input type="text" name="title" defaultValue="hello" />
508+
<input type="submit" name="button" value="save" />
509+
<input type="submit" name="button" value="delete" ref={inputRef} />
510+
<button name="button" value="edit" ref={buttonRef}>
511+
Edit
512+
</button>
513+
</form>
514+
,
515+
</>,
505516
);
506517
});
507518

@@ -522,6 +533,11 @@ describe('ReactDOMForm', () => {
522533
expect(button).toBe('edit');
523534
expect(title).toBe('hello');
524535

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

0 commit comments

Comments
 (0)