How to use multiple forms on a single page? #1569
-
Hi Remix team and community! 👋 I'm just learning about Remix and wondering how to do loading states and optimistic updates when there are multiple forms on the same page. The Also, as far as I understand there can be just a single action defined per page, so I'm not even sure whether I could implement the serverside logic without opting out of the Remix form handling. How do you recommend dealing with multiple forms on the same page without them stepping onto each others' feet? Or is there something to improve that on the roadmap? |
Beta Was this translation helpful? Give feedback.
Replies: 6 comments 2 replies
-
It gets a bit verbose but here's how you can do it: import type { ActionFunction } from 'remix';
import { Form, json, useTransition } from 'remix';
enum FormNames {
FIRST_NAME_FORM = 'firstNameForm',
LAST_NAME_FORM = 'lastNameForm',
}
export const action: ActionFunction = async ({ request }) => {
await new Promise((res) => setTimeout(res, 1000));
const formData = await request.formData();
const formName = formData.get('formName');
switch (formName) {
case FormNames.FIRST_NAME_FORM:
console.log('handle firstName form server side');
return json({ firstName: formData.get('firstName') });
case FormNames.LAST_NAME_FORM:
console.log('handle lastName form server side');
return json({ firstName: formData.get('lastName') });
default:
// handle default server side
}
};
const Forms = () => {
const transition = useTransition();
const formName = transition.submission?.formData.get('formName');
let firstNameFormText = 'Submit first name';
let lastNameFormText = 'Submit last name';
switch (formName) {
case FormNames.FIRST_NAME_FORM:
firstNameFormText =
transition.state === 'submitting'
? 'Saving...'
: transition.state === 'loading'
? 'Loading...'
: 'Submit first name';
break;
case FormNames.LAST_NAME_FORM:
lastNameFormText =
transition.state === 'submitting'
? 'Saving...'
: transition.state === 'loading'
? 'Loading...'
: 'Submit last name';
break;
default:
// handle default
}
return (
<div>
<Form method='post'>
<label>
First name
<input name='firstName' type='text' />
</label>
<button name='formName' value={FormNames.FIRST_NAME_FORM}>
{firstNameFormText}
</button>
</Form>
<Form method='post'>
<label>
Last name
<input name='lastName' type='text' />
</label>
<button name='formName' value={FormNames.LAST_NAME_FORM}>
{lastNameFormText}
</button>
</Form>
</div>
);
};
export default Forms; |
Beta Was this translation helpful? Give feedback.
-
If multiple submission could/should happen at the same time, one In such cases, using For references for different types of requests, this cheatsheet might help. |
Beta Was this translation helpful? Give feedback.
-
You can also use hidden inputs to identify the form on the server. // in your action
const requestType = form.get("request-type");
switch (requestType) {
case "change-name":
const name = form.get("name");
...
case ...
}
// in your markup
<form method="post>
<input value="change-name" name="request-type" readOnly hidden />
...
</form> |
Beta Was this translation helpful? Give feedback.
-
Could this proposal #2782 a good option? |
Beta Was this translation helpful? Give feedback.
-
You can try remix-validated-form form library |
Beta Was this translation helpful? Give feedback.
-
did remix add any improvements to handle this? |
Beta Was this translation helpful? Give feedback.
It gets a bit verbose but here's how you can do it: