Formik: Nested <Formik /> Components should have something like form.stopPropagation

Created on 3 Jan 2019  路  11Comments  路  Source: formium/formik

馃殌 Feature request

Current Behavior

I am referring to this comment: https://github.com/jaredpalmer/formik/issues/826#issuecomment-425961649

In this comment, nesting Formik Components is mentioned like so:

<Formik>
 {(formik) => (
    <form onSubmit={formik.handleSubmit}>
    <Formik>
       {(subformik) => (
          <form >
              <input name="username" onChange={subformik.handleChange} value={subformik.values.username} />
               {/** i also have access to formik here too */}
              <button onClick={() => subformik.submitForm()}>Submit Inner</button>
              <button onClick={() => formik.submitForm()}>Submit Outer</button>
          </form>
        )}
    </Formik>
    </form>
  )}
</Formik>

When I am in the username field, and hit <Enter>, the browser triggers a submit event on both forms, so that formik.handleSubmit and subformik.handleSubmit is triggered.

Desired Behavior

What I would like is a possibility within subformik.handleSubmit to stop propagation of the submit event to the outer form.

Problem is that nesting form elements is not valid HTML, and thus, there might be no solution at all.

Who does this impact? Who is this for?

I have a form, in which a user can create an entity (like a support ticket). This entity has a relation to another entity (like a foreign key to something like e.g. customer).
The chosen foreign key should be available to the outer form. When clicking the chosen foreign key, a modal pops up where the foreign key can be searched or created. On creation of the foreign key entity (inner form), I don't want the outer form to be submitted.

Describe alternatives you've considered

An alternative would be to not nest Formik components, but this will tremendously bloat the structure in such a case.

Formik Duplicate Needs More Information Feature Request

Most helpful comment

it seems this works for me in the inner form

      <form
        onSubmit={e => {
          e.stopPropagation();
          handleSubmit(e);
        }}
      >

All 11 comments

I have this problem too, even though I already use React.portal to prevent nested <form> on HTML.

I have the same problem. My workaround is to intercept onSubmit on the form to cancel the event propagation.

render() {
 <Formik  (...) >
       {  formikProps => 
            <form onSubmit={this.handleSubmit.bind(this, formikProps)} >
               (...)
            </form>
        }
</Formik>
}

handleSubmit = (formikProps, event) => {
    event.stopPropagation();
    formikProps.handleSubmit(event);
}

Not sure it is the best solution, but it works for me.

Nesting <form> elements is invalid HTML, which is why I was proposing a simulated form component that would look something like this. Calling e.preventDefault() on enter in onKeyDownCapture prevents the outer Form from submitting.

I'd like to not promote invalid HTML. The correct workaround is to fake a form with key listeners / event handlers etc or tell your designer to come up with something else.

I also don't know how subFormik becomes aware of where it is being rendered? We could maybe call event.stopPropagation() on every submit? Idk what the impact of that would be.

@sebst Can you point to documentation and specs about proper usage of event.stopPropagation() and discuss pros/cons?

I've been using event.stopPropagation() in combination with event.preventDefault() in our forms (now migrating to Formik) precisely due to the mentioned issue and I have yet to observe any downside. BTW Using portals is definitely recommended, but doesn't help in this case - I'm guessing because events are synthetic in React and propagate all the way through the component tree?

The use case we have for "nesting" form components is the following:
There's a select inside of a form. The user can either select an existing item or choose an option to add a new item. If they select to add a new item, a dialog appears where they can add it. After they add it (by submitting a form in the dialog), it is automatically selected in the select of the original form - which we don't want to submit for obvious reasons.

I'm running into this issue and our use case is complex as well. We have an outer form for editing a resource and inner form for sharing the resource. It's quite the situation and Formik handles it all gracefully.

Anyway, I think overriding FormikForm.handleSubmit with stopPropagation is a good workaround, but the FormikTypes don't allow for a overriding onSubmit.

In general, I think the best option for the library would be to add a disablePropagation option to the Formik Form component.

You don't have to have invalid HTML to run into this. You can get there using a React Portal (As in: A form that opens a modal to allow editing one of its components, which in turn contains ... another form).

In HTML, this can be valid, as Modal-Portals are usually appended to the document. But since react is insisting on routing the submit event through the portal, we end up with the exact same problem.

Still, I wouldn't tackle this in formik. Portals are finicky regarding events anyway, and there are people who want to be able to disable that forwarding anyway (see https://github.com/facebook/react/issues/11387).

it seems this works for me in the inner form

      <form
        onSubmit={e => {
          e.stopPropagation();
          handleSubmit(e);
        }}
      >

You are supposed to add onSubmit handler which stops propagation. Note that nesting form鈥檚 results in invalid HTML

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Jungwoo-An picture Jungwoo-An  路  3Comments

giulioambrogi picture giulioambrogi  路  3Comments

PeerHartmann picture PeerHartmann  路  3Comments

outaTiME picture outaTiME  路  3Comments

najisawas picture najisawas  路  3Comments