Form
blode-ui/formFreeComponent
A form component with validation powered by React Hook Form and Zod.
Install it
npx shadcn@latest add https://raw.githubusercontent.com/mblode/blode-ui/main/public/r/form.jsonSource
1"use client";23import { mergeProps } from "@base-ui/react/merge-props";4import { useRender } from "@base-ui/react/use-render";5import type * as React from "react";6import { createContext, isValidElement, useContext, useId, useMemo } from "react";7import { Controller, FormProvider, useFormContext, useFormState } from "react-hook-form";8import type { ControllerProps, FieldPath, FieldValues } from "react-hook-form";910import { cn } from "@/lib/utils";11import { Label } from "@/components/ui/label";1213const Form = FormProvider;1415interface FormFieldContextValue<16 TFieldValues extends FieldValues = FieldValues,17 TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,18> {19 name: TName;20}2122const FormFieldContext = createContext<FormFieldContextValue>({} as FormFieldContextValue);2324const FormField = <25 TFieldValues extends FieldValues = FieldValues,26 TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,27>({28 ...props29}: ControllerProps<TFieldValues, TName>) => {30 const value = useMemo(() => ({ name: props.name }), [props.name]);3132 return (33 <FormFieldContext.Provider value={value}>34 <Controller {...props} />35 </FormFieldContext.Provider>36 );37};3839interface FormItemContextValue {40 id: string;41}4243const FormItemContext = createContext<FormItemContextValue>({} as FormItemContextValue);4445const useFormField = () => {46 const fieldContext = useContext(FormFieldContext);47 const itemContext = useContext(FormItemContext);48 const { getFieldState } = useFormContext();49 const formState = useFormState({ name: fieldContext.name });50 const fieldState = getFieldState(fieldContext.name, formState);5152 if (!fieldContext) {53 throw new Error("useFormField should be used within <FormField>");54 }5556 const { id } = itemContext;5758 return {59 formDescriptionId: `${id}-form-item-description`,60 formItemId: `${id}-form-item`,61 formMessageId: `${id}-form-item-message`,62 id,63 name: fieldContext.name,64 ...fieldState,65 };66};6768const FormItem = ({ className, ...props }: React.ComponentProps<"div">) => {69 const id = useId();70 const value = useMemo(() => ({ id }), [id]);7172 return (73 <FormItemContext.Provider value={value}>74 <div className={cn("grid gap-2", className)} data-slot="form-item" {...props} />75 </FormItemContext.Provider>76 );77};7879const FormLabel = ({ className, ...props }: React.ComponentProps<typeof Label>) => {80 const { error, formItemId } = useFormField();8182 return (83 <Label84// … truncated
What it pulls in
npm packages
Other registry items
Files it writes
More from blode/ui
All 85 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Accordionaccordion | blode/ui | Components | Free | 2 deps | |
| Alertalert | blode/ui | Components | Free | no deps | |
| Alert Dialogalert-dialog | blode/ui | Components | Free | 1 dep | |
| Ask User Questionsask-user-questions | blode/ui | Components | Free | 1 dep | |
| Aspect Ratioaspect-ratio | blode/ui | Components | Free | 1 dep | |
| Attachmentattachment | blode/ui | Components | Free | 1 dep | |
| Autocompleteautocomplete | blode/ui | Components | Free | 1 dep | |
| Avataravatar | blode/ui | Components | Free | 1 dep |
