React Router adapter
This was previously the Remix adapter. Since Remix v3 has merged with React Router v7, we now only have a React Router adapter.
Server-side validation
One of the core features of this library is that you can re-use your validation on the server. Let's use this schema as an example:
const schema = z.object({
firstName: z
.string()
.min(1, { message: "First name is required" }),
lastName: z
.string()
.min(1, { message: "Last name is required" }),
email: z
.string()
.min(1, { message: "Email is required" })
.email("Must be a valid email"),
});All you need to do is call parseFormData with the request and the schema.
export const action = async ({
request,
}: DataFunctionArgs) => {
const result = await parseFormData(request, schema);
if (result.error) {
// validationError comes from `@rvf/react-router`
return validationError(
result.error,
result.submittedData,
);
}
const { firstName, lastName, email } = result.data;
// Do something with the data
};When we use the validationError to return our validation errors,
the useForm or ValidatedForm in our route component will automatically pick up those errors.
If you also pass result.submittedData to as the second argument to validationError,
it will automatically repopulate the form with the data submitted by the user.
Caveats
If you have more than one form active on the page, you'll need to take some extra steps to ensure you don't show errors on the wrong form.
const form = useForm({
validator,
id: "form-1",
})
return (
<form {...form.getFormProps()}>
{/* You don't need this part if you're using
`ValidatedForm` instead of `useForm` */}
{form.renderFormIdInput()}
{/* The rest of the form */}
</form>
)Example
Try disabling JavaScript in your browser to see how server validation errors are handled.
Server validation with React Router
API differences
The API of useForm and ValidatedForm are almost identical to the base @rvf/react API.
The main difference is that useForm can accept many of the props you would normally pass
to Form or useSubmit from Remix. In order for these to work correctly,
you should pass them to the useForm hook instead of the Form component.
form or Form?
Normally, with Remix, you would use the Form component for most of your forms.
When using RVF though, you don't need to do that.
useForm calls preventDefault on the form's submit callback to take control
of the form submission.