Typesafe forms without compromises or fancy abstractions. Built for react-hook-form and your favorite validation library.
This library is a very thin wrapper around react-hook-form and just extends it with awesome type safety.
Currently supported: zod, valibot, yup
# npm
npm install @jlns/form
# Yarn
yarn add @jlns/form
# pnpm
pnpm add @jlns/form
# Bun
bun add @jlns/form
or just copy paste them into your project. You can find the code here.
Create your Form Hooks outside of React. This can even be some different file.
import { createZodForm } from "@jlns/form/zod";
// Destructure the form hooks and name them however you want
const [useProfileForm, useProfileFormContext] = createZodForm(
z.object({
firstName: z.string(),
lastName: z.string(),
address: z.object({
street: z.string(),
city: z.string(),
zip: z.string(),
}),
})
);
Use the Form Hook like you would normally do with react-hook-form
"use client";
const ProfileForm = () => {
const form = useProfileForm();
return (
<Form {...form}>
<form
onSubmit={form.handleSubmit(({ firstName }) => {
alert(firstName);
})}
>
...
</form>
</Form>
);
};
Consume the form deep down in some nested components with the Context Hook
const Address = () => {
const form = useProfileFormContext();
return (
<div>
<input {...form.register("address.street")} />
<input {...form.register("address.city")} />
<input {...form.register("address.zip")} />
</div>
);
};
...
const FullAddress = () => {
const form = useProfileFormContext();
const [street, zip, city] = form.watch([
"address.street",
"address.zip",
"address.city",
]);
if (!street || !zip || !city) return null;
return (
<p>
{street}, {zip} {city}
</p>
);
};
If you don't need to use the Context, just do the following
import { useZodForm } from "@jlns/form/zod";
const ProfileForm = () => {
const form = useZodForm({
schema: z.object({
firstName: z.string(),
lastName: z.string(),
}),
});
return (
<Form {...form}>
<form
onSubmit={form.handleSubmit(({ firstName }) => {
alert(firstName);
})}
>
<input {...form.register("firstName")} />
<input {...form.register("lastName")} />
</form>
</Form>
);
};
Zod
import { createZodForm, useZodForm } from "@jlns/form/zod";
Valibot
import { createValibotForm, useValibotForm } from "@jlns/form/valibot";
Yup
import { createYupForm, useYupForm } from "@jlns/form/yup";
The package was highly inspired by the blog post from brendonovich aswell as some implementation from Julius.