Form Errors

Field-Level and Form-Level Errors

A field-level error belongs to one input and appears next to it (fieldState.error, or errors.email). A form-level error belongs to the submission: the network failed, or the stock ran out. React Hook Form 351,018 keeps these under the root key, set with setError() once the server answers:

src/app/checkout.tsx: turning the server's answer into a form-level error (excerpt)TSX
  const onValid = async (form: CheckoutForm) => {
    try {
      const result = await placeOrder(form, useCart.getState().items);
      if ('error' in result) {                  // the server said no: a form-level error
        setError('root.server', { message: result.error });
        return;
      }
      useCart.getState().clear();
      setOrderId(result.orderId);
    } catch {
      // ...a network failure sets a root error too: "BookNest is unreachable. Try again."
    }

A banner above the fields renders errors.root?.server?.message. handleSubmit calls onValid only when the resolver passes, and isSubmitting stays true until its promise settles. Field errors clear as each field is fixed; root errors are cleared at the start of the next handleSubmit.