Skip to content

Latest commit

 

History

History
162 lines (123 loc) · 3.21 KB

README.md

File metadata and controls

162 lines (123 loc) · 3.21 KB

@jlns/form

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

Installation

# 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.

Usage

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>
  );
};

Validation Libraries

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.