Form
The form system consists of two main components:
FormWrapper
- A container component that wraps form inputs, handles form submission, and sets the input layout orientation to eithervertical
orhorizontal
FormInput
- A set of input components for different data types
Usage
The FormInput
components generate fields with the correct:
- Labels
- Input types
- Validation feedback
- Accessibility attributes
Form with Zod and React Hook Form
import { useForm } from "react-hook-form";import { zodResolver } from "@hookform/resolvers/zod";import { z } from "zod";import { Button, FormInput, FormWrapper } from "@harnessio/ui/components";
// ...
/** * 1️⃣ Define the validation schema with zod */const formSchema = z.object({ /** 💡 As a best practice, use trim() to remove whitespace from the input */ name: z.string().trim().min(3, "Input must be at least 3 characters"),
// 🚨 z.coerce.number() - Must be used for number fields // https://github.com/shadcn-ui/ui/issues/421#issuecomment-1561080201 age: z.coerce.number().min(1, "Number must be at least 1"), comment: z.string().trim().min(10, "Comment must be at least 10 characters"),});
// ...
/** 2️⃣ Infer the type from the schema */const FormValuesType = z.infer<typeof formSchema>;
function FormWithZodAndReactHookForm() { /** 3️⃣ Initialize react-hook-form with zod resolver */ const formMethods = useForm<FormValuesType>({ resolver: zodResolver(formSchema), defaultValues: { name: "John doe", age: 1, comment: "Lorem ipsum", }, });
/** 4️⃣ Extract register and handleSubmit from formMethods */ const { register, handleSubmit } = formMethods;
/** 6️⃣ Handle form submission */ const onSubmit = (data: FormValuesType) => { // ... };
/** 5️⃣ Use FormWrapper with formMethods and onSubmit */ return ( <FormWrapper {...formMethods} onSubmit={handleSubmit(onSubmit)} orientation="vertical"> <FormInput.Text {...register("name")} label="Name" /> <FormInput.Number {...register("age")} label="Age" /> <FormInput.Textarea {...register("comment")} label="Comment" /> <Button type="submit">Submit</Button> </FormWrapper> );}
Form in Dialog
The FormWrapper
should be placed inside the Dialog.Body
and contain an id
.
The submit button should be in the Dialog.Footer
with type="submit"
and a form
attribute set to the form’s id
.
import { useForm } from "react-hook-form";import { zodResolver } from "@hookform/resolvers/zod";import { z } from "zod";import { Button, FormInput, FormWrapper, Dialog } from "@harnessio/ui/components";
// ...
/** * 1️⃣ Define the validation schema with zod */const formSchema = z.object({ /** 💡 As a best practice, use trim() to remove whitespace from the input */ name: z.string().trim().min(3, "Input must be at least 3 characters"),});
// ...
/** 2️⃣ Infer the type from the schema */const FormValuesType = z.infer<typeof formSchema>;
function FormWithZodAndReactHookForm() { /** 3️⃣ Initialize react-hook-form with zod resolver */ const formMethods = useForm<FormValuesType>({ resolver: zodResolver(formSchema), defaultValues: { name: "John doe" }, });
/** 4️⃣ Extract register and handleSubmit from formMethods */ const { register, handleSubmit } = formMethods;
/** 6️⃣ Handle form submission */ const onSubmit = (data: FormValuesType) => { // ... };
/** 5️⃣ Use FormWrapper with formMethods and onSubmit */ return ( <Dialog.Root> <Dialog.Trigger asChild> <Button>Open Dialog with Form</Button> </Dialog.Trigger>
<Dialog.Content> <Dialog.Header> <Dialog.Title>Form</Dialog.Title> </Dialog.Header>
<Dialog.Body> <FormWrapper id="id-form" {...formMethods} onSubmit={handleSubmit(onSubmit)}> <FormInput.Text {...register("name")} label="Name" /> </FormWrapper> </Dialog.Body>
<Dialog.Footer> <Dialog.Close>Cancel</Dialog.Close> <Button type="submit" form="id-form" variant="primary">Submit</Button> </Dialog.Footer> </Dialog.Content> </Dialog.Root> );}