Repository: facebook/react
File: packages/react-dom-bindings/src/events/plugins/FormActionEventPlugin.js (JavaScript)

Code before:
    // its deepest target won't be the actual form that's being submitted.
    return;
  }
  const formInst = maybeTargetInst;
  const form: HTMLFormElement = (nativeEventTarget: any);
  let action = coerceFormActionProp(
    (getFiberCurrentPropsFromNode(form): any).action,
  );
  let submitter: null | void | HTMLInputElement | HTMLButtonElement =
    (nativeEvent: any).submitter;
  let submitterAction;
  if (submitter) {
    const submitterProps = getFiberCurrentPropsFromNode(submitter);
    submitterAction = submitterProps
      ? (submitterProps: any).formAction
      : submitter.getAttribute('formAction');
    if (submitterAction != null) {
      // The submitter overrides the form action.
      action = submitterAction;
      // If the action is a function, we don't want to pass its name
      // value to the FormData since it's controlled by the server.
      submitter = null;
    }
  }

  const event = new SyntheticEvent(
    'action',
    'action',
    null,
    nativeEvent,
    nativeEventTarget,
  );

  function submitForm() {
    if (nativeEvent.defaultPrevented) {
      // An earlier event prevented form submission. If a transition update was
      // also scheduled, we should trigger a pending form status — even if
      // no action function was provided.
      if (didCurrentEventScheduleTransition()) {
        // We're going to set the pending form status, but because the submission
        // was prevented, we should not fire the action function.
        const formData = submitter
          ? createFormDataWithSubmitter(form, submitter)
          : new FormData(form);
        const pendingState: FormStatus = {
          pending: true,
          data: formData,
          method: form.method,
          action: action,
        };
        if (__DEV__) {

Review comment (bug):
The submitterAction that's coming from `formAction` needs to be coerced too. Technically it was wrong before because it wasn't ignoring boolean/symbol and was treating them as the submitter taking over.

Code after:
    // If we're inside a parent root that itself is a parent of this root, then
    // its deepest target won't be the actual form that's being submitted.
    return;
  }
  const formInst = maybeTargetInst;
  const form: HTMLFormElement = (nativeEventTarget: any);
  let action = coerceFormActionProp(
    (getFiberCurrentPropsFromNode(form): any).action,
  );
  let submitter: null | void | HTMLInputElement | HTMLButtonElement =
    (nativeEvent: any).submitter;
  let submitterAction;
  if (submitter) {
    const submitterProps = getFiberCurrentPropsFromNode(submitter);
    submitterAction = submitterProps
      ? coerceFormActionProp((submitterProps: any).formAction)
      : // The built-in Flow type is ?string, wider than the spec
        ((submitter.getAttribute('formAction'): any): string | null);
    if (submitterAction !== null) {
      // The submitter overrides the form action.
      action = submitterAction;
      // If the action is a function, we don't want to pass its name
      // value to the FormData since it's controlled by the server.
      submitter = null;
    }
  }

  const event = new SyntheticEvent(
    'action',
    'action',
    null,
    nativeEvent,
    nativeEventTarget,
  );

  function submitForm() {
    if (nativeEvent.defaultPrevented) {
      // An earlier event prevented form submission. If a transition update was
      // also scheduled, we should trigger a pending form status — even if
      // no action function was provided.
      if (didCurrentEventScheduleTransition()) {
        // We're going to set the pending form status, but because the submission
        // was prevented, we should not fire the action function.
        const formData = submitter
          ? createFormDataWithSubmitter(form, submitter)
          : new FormData(form);
        const pendingState: FormStatus = {
          pending: true,
          data: formData,
          method: form.method,
          action: action,