Reddot UI Library

Docs
Form

Form

Building forms with React Hook Form and Zod.

Forms are complex web components that require careful design. Well-designed HTML forms should be:

  • Semantically structured
  • Easy to navigate
  • Accessible with ARIA attributes
  • Support client and server-side validation
  • Consistently styled

This guide demonstrates building forms using:

Features

The <Form /> component provides:

  • Composable form components
  • <FormField /> for controlled form fields
  • Zod validation
  • Accessibility handling
  • Unique ID generation
  • Correct aria attribute application
  • Compatibility with Radix UI components
  • Flexible schema support
  • Full markup and styling control

Anatomy

<Form>
  <FormField
    control={...}
    name="..."
    render={() => (
      <FormItem>
        <FormLabel />
        <FormControl>
          {/* Your form field */}
        </FormControl>
        <FormDescription />
        <FormMessage />
      </FormItem>
    )}
  />
</Form>

Installation

$npx shadcn@latest add https://reddot.dottools.xyz/r/form.json

Usage

Create a form schema

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

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

Define a form

Use the useForm hook from react-hook-form to create a form.

import { zodResolver } from "@hookform/resolvers/zod"
import { useForm } from "react-hook-form"
import { z } from "zod"
 
const form = useForm<z.infer<typeof formSchema>>({
  resolver: zodResolver(formSchema),
  defaultValues: {
    username: "",
  },
})

Build your form

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

import { Button } from "@/components/ui/button"
import {
  Form,
  FormControl,
  FormDescription,
  FormField,
  FormItem,
  FormLabel,
  FormMessage,
} from "@/components/ui/form"
import { Input } from "@/components/ui/input"
 
function onSubmit(values: z.infer<typeof formSchema>) {
  // Do something with the form values.
  // ✅ This will be type-safe and validated.
  console.log(values)
}
 
return (
  <Form {...form}>
    <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
      <FormField
        control={form.control}
        name="username"
        render={({ field }) => (
          <FormItem>
            <FormLabel>Username</FormLabel>
            <FormControl>
              <Input placeholder="shadcn" {...field} />
            </FormControl>
            <FormDescription>
              This is your public display name.
            </FormDescription>
            <FormMessage />
          </FormItem>
        )}
      />
      <Button type="submit">Submit</Button>
    </form>
  </Form>
)

Examples

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

References