Skip to content
Logic2BUI

Search docs

Search components and documentation

New
Menu

Form

Building forms with react-hook-form and zod.

This is your public display name.

Installation

npx logic2b@next add form

Anatomy

import { useForm } from "react-hook-form"
import { zodResolver } from "@hookform/resolvers/zod"
import { z } from "zod"

import {
  Form,
  FormControl,
  FormDescription,
  FormField,
  FormItem,
  FormLabel,
  FormMessage,
} from "@/components/ui/form"

const formSchema = z.object({
  username: z.string().min(2),
})

function ProfileForm() {
  const form = useForm<z.infer<typeof formSchema>>({
    resolver: zodResolver(formSchema),
    defaultValues: { username: "" },
  })

  return (
    <Form {...form}>
      <form onSubmit={form.handleSubmit(console.log)}>
        <FormField
          control={form.control}
          name="username"
          render={({ field }) => (
            <FormItem>
              <FormLabel>Username</FormLabel>
              <FormControl>
                <input {...field} />
              </FormControl>
              <FormDescription>Your public display name.</FormDescription>
              <FormMessage />
            </FormItem>
          )}
        />
      </form>
    </Form>
  )
}

FormField wraps react-hook-form’s Controller and provides field context to FormLabel, FormControl, FormDescription and FormMessage — they read validation state (error, id) from that context, so labels and messages stay wired to the right input automatically.

Usage notes

Form is an alias for react-hook-form’s FormProvider, so spread your useForm return value onto it. The pieces below consume field context.

Examples

Sign In

Validate an email and password with zod.

Textarea

This appears on your public profile.

Accessibility

  • FormControl sets id, aria-describedby and aria-invalid from field context, so the label, description and error message are all wired to the input without manual htmlFor / id bookkeeping.
  • On validation failure FormMessage renders the error text with the id referenced by aria-describedby, and FormLabel turns destructive — the invalid state is conveyed both visually and to screen readers.
  • Because each control gets a unique generated id, labels always point at the right input even when the field is reused in a list.

Live playground

Edit the component props and inspect the exact JSX before copying it. The preview loads only when this section enters the viewport.

Generated JSX
const form = useForm({
  defaultValues: { username: "" },
})

return (
  <Form {...form}>
    <form onSubmit={form.handleSubmit(console.log)}>
      <FormField
        control={form.control}
        name="username"
        rules={{ required: "Username is required." }}
        render={({ field }) => (
          <FormItem>
            <FormLabel>Username</FormLabel>
            <FormControl>
              <Input
                {...field}
                placeholder={"logic2b"}
              />
            </FormControl>
            <FormDescription>{"This is your public display name."}</FormDescription>
            <FormMessage />
          </FormItem>
        )}
      />
      <Button type="submit">Save profile</Button>
    </form>
  </Form>
)

API reference

Generated from the public TypeScript exports in src/ui/form.tsx.

View JSON

useFormField

Hook
(): { invalid: boolean; isDirty: boolean; isTouched: boolean; isValidating: boolean; error?: FieldError; id: string; name: string; formItemId: string; formDescriptionId: string; formMessageId: string; }

Form

Component

Direct alias of FormProvider.

FormItem

Component
Props: React.ComponentProps<"div">

FormLabel

Component
Props: React.ComponentProps<typeof Label>

FormControl

Component
Props: React.ComponentProps<typeof Slot.Root>

FormDescription

Component
Props: React.ComponentProps<"p">

FormMessage

Component
Props: React.ComponentProps<"p">

FormField

Component
Props: ControllerProps<TFieldValues, TName>

Accessibility contract

Machine-readable behavior and consumer responsibilities for form.

View JSON
Support
Authored behavior
Pattern
form validation
React Hook Form + Radix Label

Built-in semantics

  • FormControl derives id, aria-invalid and aria-describedby from field state.
  • Descriptions and error messages receive stable ids.

Consumer responsibilities

  • Render FormLabel and useful error text; move focus or provide a summary after failed submission.