Form submission

We recommend using Next.JS form actions to handle form submissions. The solution requires two parts:

  1. A server action
  2. 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 onSubmit handler passed to the useForm hook
  • 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 '@/ui/components/forms/form';
import { useForm } from '@/ui/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>
  );
};