0
0
RemixDebug / FixBeginner · 4 min read

How to Handle Multiple Forms in Remix: Fix and Best Practices

In Remix, to handle multiple forms on the same page, assign each form a unique name or action attribute and check request.formData() in the action function to identify which form was submitted. This lets you run different logic for each form within a single action handler.
🔍

Why This Happens

When you have multiple forms on one Remix page but use a single action function without distinguishing which form was submitted, Remix treats all form submissions the same. This causes your server code to run the same logic regardless of the form, leading to unexpected behavior or errors.

tsx
export const action = async ({ request }) => {
  const formData = await request.formData();
  // No check for which form submitted
  const data = formData.get('input');
  // Process data assuming only one form
  return { message: `Received: ${data}` };
};

export default function Page() {
  return (
    <>
      <form method="post">
        <input name="input" />
        <button type="submit">Submit Form 1</button>
      </form>
      <form method="post">
        <input name="input" />
        <button type="submit">Submit Form 2</button>
      </form>
    </>
  );
}
Output
Both forms submit to the same action, so the server cannot tell which form was submitted, causing confusion or wrong processing.
🔧

The Fix

Give each form a unique name or action attribute or include a hidden input to identify the form. Then, in the action function, check this identifier to run the correct logic for each form.

tsx
export const action = async ({ request }) => {
  const formData = await request.formData();
  const formName = formData.get('formName');

  if (formName === 'form1') {
    const data = formData.get('input1');
    return { message: `Form 1 received: ${data}` };
  }

  if (formName === 'form2') {
    const data = formData.get('input2');
    return { message: `Form 2 received: ${data}` };
  }

  return { message: 'Unknown form submitted' };
};

export default function Page() {
  return (
    <>
      <form method="post">
        <input name="input1" />
        <input type="hidden" name="formName" value="form1" />
        <button type="submit">Submit Form 1</button>
      </form>
      <form method="post">
        <input name="input2" />
        <input type="hidden" name="formName" value="form2" />
        <button type="submit">Submit Form 2</button>
      </form>
    </>
  );
}
Output
Submitting Form 1 returns: { message: 'Form 1 received: ...' } Submitting Form 2 returns: { message: 'Form 2 received: ...' }
🛡️

Prevention

Always include a hidden input or unique identifier in each form to distinguish them in your action handler. Use clear naming conventions for inputs and form identifiers. Test each form separately to ensure the correct logic runs. Consider splitting complex forms into separate routes if needed for clarity.

⚠️

Related Errors

1. Missing form identifier: Causes all forms to trigger the same logic, leading to bugs.

2. Duplicate input names: Can cause unexpected data overwrites in formData.

3. Forgetting method="post": Forms default to GET, which Remix action does not handle.

Key Takeaways

Use a hidden input or unique attribute to identify each form in Remix.
Check the form identifier in the action function to run form-specific logic.
Avoid using the same input names across multiple forms without distinction.
Test each form submission separately to ensure correct handling.