Form submission
We recommend using Next.JS form actions to handle form submissions. The solution requires two parts:
- A server action
- The form component
Server action
the server action should accept a Partial<T> type where T is the form values.
If the server action throws an error the form will automatically change to
an error state and display the error message in the <FormServerError /> component.
If the server action does not throw an error the form will automatically change to a success state. You then have the opportunity to either display a success state, redirect to a different URL, or reset the form values.
// login-form/actions.ts
import { login } from '@/api/auth';
export const loginAction = async (
values: Partial<{ email: string; password: string }>,
) => {
try {
await login(values.email, values.password);
} catch (error) {
throw new Error('Failed to login');
}
// You don't need to return anything if the action is successful.
};Form component
The form component:
- Calls the action inside the
onSubmithandler passed to theuseFormhook - Renders the
<FormServerError />component if the action throws an error - Renders the
<FieldErrorSummary />component if the action throws field-level validation errors
// login-form/form.tsx
import { Form } from '@/components/forms/form';
import { useForm } from '@/components/forms/hooks/use-form';
import { loginAction } from './actions';
export const LoginForm = () => {
const form = useForm<{ email: string; password: string }>({
onSubmit: async ({ values }) => {
await loginAction(values);
},
});
return (
<FormRoot context={form}>
<FormStatus>
{/* Render any server errors from the action */}
{form.serverError && (
<FormServerError
title="Could not sign in"
errorMessage={form.serverError}
/>
)}
{/* Render a summary of field level errors */}
<FieldErrorSummary
title="There are errors in your submission"
subtitle="Please correct your input in these fields:"
fieldLabels={{
email: 'Email Address',
password: 'Password',
}}
/>
</FormStatus>
<Form>
<TextField
id="email"
name="email"
label="Email"
isRequired
autoComplete="email"
/>
<TextField
id="password"
name="password"
label="Password"
isRequired
autoComplete="current-password"
/>
<Button type="submit" loading={form.isPending}>
Login
</Button>
</Form>
</FormRoot>
);
};