I’m using React, I have a form inside of another form:
When a user clicks on a specific button, a dialog shows up, which has the form that I want to be submitted.
My 2 forms have different IDs, but when I submit the form I want (which is in the dialog), the form in the background also submits.
I’m using react-hook-form
to manage my forms, if this is also related.
I hope this image can give a little background on the situation:
I tried:
- Using different IDs for my forms
- Different
onSubmit
function names - Putting the
onSubmit
button in the<form>
tag that I want to submit - Setting different unique IDs for my submit buttons.
2
Answers
TL; DR
Use
event.stopPropagation()
outside React Hook FormhandleSubmit
:Explanations
React Hook Form
handleSubmit
fires itssubmitHandler
callback after asynchronous validation, so even if we try to useevent.stopPropagation()
inside oursubmitHandlerFunction
, it is already too late to prevent the "parent" form from being submitted as well.You can see that the "parent" form is being submitted before our
submitHandlerFunction
runs:Live demo: https://stackblitz.com/edit/vitejs-vite-66e51m?file=src%2FApp.jsx
We have to call it outside
handleSubmit
:We can also leverage some library to slightly simplify, e.g.
browser-event-utils
‘swithStopPropagation()
:More insights
As mentioned by Code Spirit in the question comments, normally a
<form>
should not be nested inside another<form>
, as per HTML spec:See also Can you nest HTML forms?
That being said, since your "child"
<form>
appears in a modal dialog, it probably is rendered in the DOM through a React Portal (e.g. if you use MUI Dialog). In that case, it is no longer nested inside the "parent" form, because the Portal "sends" its HTML content to another part of the DOM tree (in the case of MUI Dialog, as the last child of<body>
).While we now technically comply with the HTML spec, unfortunately it will still not work in React, because of the behaviour of Portals regarding events propagation:
So we are back to square one: the
"submit"
action triggers the "child" and "parent" forms…There is also a possibility to associate form elements (here the submit button) to an explicit form, as also mentioned by Code Spirit in the question comments, by using a
form="formId"
attribute on them:But this helps when these elements are outside their
<form>
(i.e. not descendants in the DOM tree). It does not break the normal event propagation.As already implied, the solution is to stop the propagation of the
"submit"
event, so that the "parent" form does not receive it, and it does not fire itsonSubmit
callback.See also submit child form that was inside another form and prevent submitting parent form, react-hook-form
But there is a subtlety with React Hook Form’s
handleSubmit
, see above explanations.if you donot want to submit another formyou can define the type of button as button for one and submit for another .