Skip to content

Form ​

React Hook Form integration with accessible labels and validation

Simple Form

Usage ​

tsx
import { Form, FormItem, FormLabel, FormControl, FormDescription, FormMessage } from '@tryvienna/ui'

<Form {...form}>
  <form onSubmit={form.handleSubmit(() => {})} className="grid gap-6 w-96">
    <FormField
      control={form.control}
      name="username"
      rules={{ required: 'Username is required' }}
      render={({ field }) => (
        <FormItem>
          <FormLabel>Username</FormLabel>
          <FormControl>
            <Input placeholder="johndoe" {...field} />
          </FormControl>
          <FormDescription>Your public display name.</FormDescription>
          <FormMessage />
        </FormItem>
      )}
    />
    <FormField
      control={form.control}
      name="email"
      rules={{
        required: 'Email is required',
        pattern: { value: /^[^\s@]+@[^\s@]+\.[^\s@]+$/, message: 'Invalid email address' },
      }}
      render={({ field }) => (
        <FormItem>
          <FormLabel>Email</FormLabel>
          <FormControl>
            <Input type="email" placeholder="john@example.com" {...field} />
          </FormControl>
          <FormDescription>We'll never share your email.</FormDescription>
          <FormMessage />
        </FormItem>
      )}
    />
    <FormField
      control={form.control}
      name="bio"
      render={({ field }) => (
        <FormItem>
          <FormLabel>Bio</FormLabel>
          <FormControl>
            <Textarea placeholder="Tell us about yourself..." {...field} />
          </FormControl>
          <FormDescription>Brief description for your profile.</FormDescription>
          <FormMessage />
        </FormItem>
      )}
    />
    <Button type="submit">Submit</Button>
  </form>
</Form>

Examples ​

Simple Form ​

Simple Form
tsx
<Form {...form}>
  <form onSubmit={form.handleSubmit(() => {})} className="grid gap-6 w-96">
    <FormField
      control={form.control}
      name="username"
      rules={{ required: 'Username is required' }}
      render={({ field }) => (
        <FormItem>
          <FormLabel>Username</FormLabel>
          <FormControl>
            <Input placeholder="johndoe" {...field} />
          </FormControl>
          <FormDescription>Your public display name.</FormDescription>
          <FormMessage />
        </FormItem>
      )}
    />
    <FormField
      control={form.control}
      name="email"
      rules={{
        required: 'Email is required',
        pattern: { value: /^[^\s@]+@[^\s@]+\.[^\s@]+$/, message: 'Invalid email address' },
      }}
      render={({ field }) => (
        <FormItem>
          <FormLabel>Email</FormLabel>
          <FormControl>
            <Input type="email" placeholder="john@example.com" {...field} />
          </FormControl>
          <FormDescription>We'll never share your email.</FormDescription>
          <FormMessage />
        </FormItem>
      )}
    />
    <FormField
      control={form.control}
      name="bio"
      render={({ field }) => (
        <FormItem>
          <FormLabel>Bio</FormLabel>
          <FormControl>
            <Textarea placeholder="Tell us about yourself..." {...field} />
          </FormControl>
          <FormDescription>Brief description for your profile.</FormDescription>
          <FormMessage />
        </FormItem>
      )}
    />
    <Button type="submit">Submit</Button>
  </form>
</Form>

With Validation Errors ​

With Validation Errors
tsx
<Form {...form}>
  <form className="grid gap-6 w-96">
    <FormField
      control={form.control}
      name="name"
      rules={{
        required: 'Name is required',
        minLength: { value: 2, message: 'Min 2 characters' },
      }}
      render={({ field }) => (
        <FormItem>
          <FormLabel>Name</FormLabel>
          <FormControl>
            <Input placeholder="Your name" {...field} />
          </FormControl>
          <FormMessage />
        </FormItem>
      )}
    />
    <FormField
      control={form.control}
      name="email"
      rules={{
        required: 'Email is required',
        pattern: { value: /^[^\s@]+@[^\s@]+\.[^\s@]+$/, message: 'Invalid email address' },
      }}
      render={({ field }) => (
        <FormItem>
          <FormLabel>Email</FormLabel>
          <FormControl>
            <Input type="email" {...field} />
          </FormControl>
          <FormMessage />
        </FormItem>
      )}
    />
    <Button type="submit">Submit</Button>
  </form>
</Form>

With Checkbox ​

With Checkbox
tsx
<Form {...form}>
  <form onSubmit={form.handleSubmit(() => {})} className="grid gap-6 w-96">
    <FormField
      control={form.control}
      name="terms"
      rules={{ validate: (v) => v === true || 'You must accept the terms' }}
      render={({ field }) => (
        <FormItem>
          <div className="flex items-center gap-2">
            <FormControl>
              <Checkbox checked={field.value} onCheckedChange={field.onChange} />
            </FormControl>
            <FormLabel>Accept terms and conditions</FormLabel>
          </div>
          <FormDescription>
            You agree to our Terms of Service and Privacy Policy.
          </FormDescription>
          <FormMessage />
        </FormItem>
      )}
    />
    <Button type="submit">Continue</Button>
  </form>
</Form>

API Reference ​

FormItem ​

Also accepts all props from div.

FormLabel ​

Also accepts all props from LabelPrimitive.Root.

FormControl ​

Also accepts all props from Slot.

FormDescription ​

Also accepts all props from p.

FormMessage ​

Also accepts all props from p.

Data Attributes ​

Componentdata-slot
Form"form-item"
FormItem"form-item"
FormLabel"form-label"
FormControl"form-control"
FormDescription"form-description"
FormMessage"form-message"