remix-run/react-router · error

Cannot submit element that is not

Error message

Cannot submit element that is not <form>, <button>, or <input type="submit|image">

What it means

React Router's submit path (useSubmit, useFetcher().submit, router.submit) extracts method/action/formData from a DOM target, but only <form>, <button>, and <input type="submit|image"> carry submission semantics. getFormSubmissionInfo() in lib/dom/dom.ts:339 throws this error when it receives any other HTMLElement. The library refuses to guess an action or method for elements that have none.

Solutions

  1. Submit the owning form instead of the control: submit(event.currentTarget.form)
  2. Or submit data directly instead of an element: submit({ q: value }, { method: 'get' })
  3. If using a button, make sure it is a real <button type="submit"> inside the <Form>
  4. Double-check that the ref/value you pass resolves to the <form> node itself

Example fix

// before
<select onChange={(e) => submit(e.currentTarget)} />
// after
<select onChange={(e) => submit(e.currentTarget.form)} />
Defensive patterns

Strategy: type-guard

Validate before calling

const el = e.currentTarget;
if (el instanceof HTMLFormElement || el instanceof HTMLButtonElement) {
  submit(el);
} else if (el instanceof HTMLInputElement && (el.type === 'submit' || el.type === 'image')) {
  submit(el);
} else if (el instanceof HTMLElement && el.form) {
  submit(el.form);
} else {
  submit(new FormData(el.form ?? undefined));
}

Type guard

function isSubmittable(el: EventTarget | null): el is HTMLFormElement | HTMLButtonElement | HTMLInputElement {
  if (!(el instanceof HTMLElement)) return false;
  return (
    el instanceof HTMLFormElement ||
    el instanceof HTMLButtonElement ||
    (el instanceof HTMLInputElement && (el.type === 'submit' || el.type === 'image'))
  );
}

Try / catch

try { submit(target) } catch (e) { if (e instanceof Error && e.message.startsWith('Cannot submit element')) { submit(target.form) } else { throw e } }

Prevention

When it happens

Trigger: Calling submit(e.currentTarget) from a <select onChange={...}> (the currentTarget is the <select>, not the form); passing an <a>, <div>, or <input type="text"> to submit(); calling router.submit(document.querySelector('#wrapper')) where the node is a non-submittable element; submitting a ref that points to a container div instead of the <Form>.

Common situations: Filter/search dropdowns that auto-submit a form on change; migrating native form code where developers submit the changed control instead of the form; refs attached to wrapper elements around the form.

Related errors


AI-assisted analysis of remix-run/react-router@6beaca3952 (2026-08-18). Data as JSON: /api/errors/bbf5177fd1b19b55. Report an issue: GitHub.

Appendix: source

Thrown at packages/react-router/lib/dom/dom.ts:340

    // Build a FormData object populated from a form and submitter
    formData = new FormData(form, target);

    // If this browser doesn't support the `FormData(el, submitter)` format,
    // then tack on the submitter value at the end.  This is a lightweight
    // solution that is not 100% spec compliant.  For complete support in older
    // browsers, consider using the `formdata-submitter-polyfill` package
    if (!isFormDataSubmitterSupported()) {
      let { name, type, value } = target;
      if (type === "image") {
        let prefix = name ? `${name}.` : "";
        formData.append(`${prefix}x`, "0");
        formData.append(`${prefix}y`, "0");
      } else if (name) {
        formData.append(name, value);
      }
    }
  } else if (isHtmlElement(target)) {
    throw new Error(
      `Cannot submit element that is not <form>, <button>, or ` +
        `<input type="submit|image">`,
    );
  } else {
    method = defaultMethod;
    action = null;
    encType = defaultEncType;
    body = target;
  }

  // Send body for <Form encType="text/plain" so we encode it into text
  if (formData && encType === "text/plain") {
    body = formData;
    formData = undefined;
  }

  return { action, method: method.toLowerCase(), encType, formData, body };
}

View on GitHub (pinned to 6beaca3952)