Shopify / shopify-app-bridge

https://shopify.dev/docs/api/app-bridge
86 stars 9 forks source link

Closing a V4 modal triggers form submission #342

Closed kylebuildsstuff closed 4 months ago

kylebuildsstuff commented 5 months ago

Describe the bug

When clicking the button to hide/close a V4 modal it triggers a form submission, despite there being no code related to form submission within the onHide callback.

This also seems to happen with the TitleBar action groups when clicking a button that did not previously have anything to do with form submission.

To Reproduce

Steps to reproduce the behaviour:

  1. Open page with a formik form and app bridge V4 modal
  2. Open modal
  3. Close modal by clicking the close button
  4. Form submission happens, even without any code that explicitly calls for it

If applicable, add screenshots to help explain your problem.

V4 app-bridge modal (The "saved" toast appears only when a change has successfully saved, which shouldn't be triggered when closing a modal but is triggered when the form is submitted):

https://github.com/Shopify/shopify-app-bridge/assets/17548405/fc960ef1-6309-4f51-bbf4-2d25115916c0

Polaris + v3 app-bridge modal (working as expected, no unintended saves triggered when closing the modal or navigating with TitleBar action groups button):

https://github.com/Shopify/shopify-app-bridge/assets/17548405/19881430-c2c7-4e38-9c2d-45810c00c176

Expected behaviour

When clicking the button to hide/close a V4 modal it should hide/close, invoking only the onHide handler and not triggering side effects like form submission.

Contextual information

Prior to app-bridge v4 I was using the Modal from Polaris. Opening and closing/hiding worked as expected and no extra form submissions were called.

With this migration closing any modal on any form page triggers a form submission, which creates the unintentional effect of saving a change. When clicking outside the modal the modal closes properly and nothing else seems to occur. Only when clicking the close button does it trigger the form submit. The onHide handler is not associated to any code that triggers a form submission.

Packages and versions

List the relevant packages you’re using, and their versions. For example:

"@shopify/app-bridge-react": "^4.1.3", "@shopify/polaris": "12.6.0", "react": "18.0.0", "formik": "^2.2.9",

Platform

Additional context

// Form.component.tsx (wraps FormComponent and passes in Formik props)
<Formik
      initialValues={initialValues}
      enableReinitialize
      onSubmit={(submittedFormValues) => {
        // This callback part gets called when modal is closed
        // before, this happened only when submitForm() was explicitly called (another formik prop)
         ...formSubmission
    >
      {(formikProps) => {
        // formikProps contains handleSubmit and passes into FormComponent as prop
        return (
          <FormComponent
            {...formikProps}
            ...
          />
        );
      }}
    </Formik>

// FormComponent.component.tsx
export const FormComponent = ({
...
// This function here is the only thing that's supposed to be called when clicking "Cancel"
const handleDeleteModalClose = () => {
    setIsDeleteModalOpen(false);  // react state variable
  };

const handleDeleteModalPrimaryAction = () => {
    handleDeleteModalClose();
    dispatch(promotionDeleteRequest...)
  };

...
return (
  <form onSubmit={handleSubmit} onReset={handleReset}>
   ...

    <Modal open={isDeleteModalOpen} onHide={handleDeleteModalClose}>
        <p>{deleteModalBody}</p>

        <TitleBar title={deleteModalTitle}>
          <button
            variant="primary"
            tone="critical"
            onClick={handleDeleteModalPrimaryAction}
          >
            Delete block
          </button>
          <button onClick={handleDeleteModalClose}>Cancel</button>
        </TitleBar>
      </Modal>
  </form>
)
abhinavkumar940 commented 4 months ago

The default type for an HTMLButton is submit. By default any <button> thats inside a <form> will trigger form submission. This is default HTML behaviour. To prevent this, you need to explicitly add the type as button. So in your case it could be

<button type="button" onClick={whatever}>close</button>
kylebuildsstuff commented 4 months ago
<button type="button" onClick={whatever}>close</button>

Wow, thank you! This works perfectly.