Docs
ReForm - React Hook Form as Nested

ReForm - React Hook Form as Nested

Building "nested" forms with React Hook Form and Zod.

Yes, forms are tricky, but they don't have to be complicated! ReForm is a re-designed version of the shadcn/ui form elements that are nested and ready to use.

We are stick to well-designed HTML forms are:

  • Well-structured and semantically correct.
  • Easy to use and navigate (keyboard).
  • Accessible with ARIA attributes and proper labels.
  • Has support for client and server side validation.
  • Well-styled and consistent with the rest of the application.

Features

The <ReForm /> component is a wrapper around the react-hook-form library. It provides a few things:

  • Composable components for building forms.
  • Each ReForm elements ex. <ReInput /> component for building nested form fields.
  • Form validation using zod.
  • Handles accessibility and error messages.
  • Uses React.useId() for generating unique IDs.
  • Applies the correct aria attributes to form fields based on states.
  • Built to work with all shadcn/ui components.
  • Bring your own schema library. We use zod but you can use anything you want.
  • You have full control over the markup and styling.

Anatomy

<ReForm>
  <ReInput name="..." label="..." description="..." placeholder="..." />
</ReForm>

Example

const schema = z.object({
  username: z.string().min(2, {
    message: "Username must be at least 2 characters.",
  }),
  password: z.string().min(8, {
    message: "Password must be at least 8 characters.",
  }),
})
 
type FormType = z.infer<typeof schema>
 
const handleSubmit: ReformSubmitHandler<FormType> = async (data) => {
  await mutation(data)
}
 
return (<ReForm<FormType> schema={schema} onSubmit={handleSubmit}>
  <ReInput
    label="Username"
    name="username"
    placeholder="username, email or phone number"
  />
  <RePassword label="Password" name="password" placeholder="password" />
  <ReErrorArea />
  <ReSubmit>Login</ReSubmit>
</ReForm>)

Installation

Dependencies

The ReForm is built using the <Form /> from shadcn/ui. See installation instructions for the Form component.

Command

pnpm dlx kodkafa@latest add re-form

Usage

Create a form schema and type

Define the shape of your form using a Zod schema. You can read more about using Zod in the Zod documentation.

"use client"
 
import { z } from "zod"
 
const formSchema = z.object({
  username: z.string().min(2).max(50),
})
 
type FormType = z.infer<typeof formSchema>

Define a schema

"use client"
 
import { z } from "zod"
 
const formSchema = z.object({
  username: z.string().min(2, {
    message: "Username must be at least 2 characters.",
  }),
})
 
// ...

Define a submit handler

// ...
type FormType = z.infer<typeof formSchema>
 
export function LoginForm() {
  // 1. Define a submit handler.
  function handleSubmit<FormType>(values) {
    // Do something with the form values.
    // ✅ This will be type-safe and validated.
    console.log(values)
  }
}

Build your form

We can now use the <ReForm /> components to build our form.

// ...
import { ReErrorArea, ReForm } from "@/components/ui/re-form"
import { ReInput } from "@/components/ui/re-input"
import { ReSubmit } from "@/components/ui/re-submit"
 
// ...
export function LoginForm() {
  // ...
  return (
    <ReForm<FormType> schema={formSchema} onSubmit={handleSubmit}>
      <ReInput
        label="Username"
        name="username"
        placeholder="username, email or phone number"
      />
      // ...
      <ReSubmit>Login</ReSubmit>
    </ReForm>
  )
}

Done

That's it. You now have a fully accessible form that is type-safe with client-side validation.

This is your public display name.

Examples

Error

You can use the <ReErrorArea /> component to display error messages coming from the server.

This is your public display name.

Validation Error from Backend

This is your public display name.

See the following links for more examples on how to use the <ReForm /> component with other components: