Form
muffled-ui-registry/formFreeComponent
React Hook Form field wiring with Zod validation. Mono labels, grotesk hints, destructive errors.
Live preview
live · rendered by the registry
Rendered by muffled-ui-registry on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://ui.muffled.studio/r/form.jsonSource
1import { mergeProps } from "@base-ui/react/merge-props"2import { useRender } from "@base-ui/react/use-render"3import * as React from "react"4import {5 Controller,6 type ControllerProps,7 type FieldPath,8 type FieldValues,9 FormProvider,10 useFormContext,11 useFormState,12} from "react-hook-form"1314import { cn } from "@/registry/lib/surface"15import { Label } from "@/registry/ui/label"1617const Form = FormProvider1819type FormFieldContextValue<20 TFieldValues extends FieldValues = FieldValues,21 TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,22> = {23 name: TName24}2526const FormFieldContext = React.createContext<FormFieldContextValue>(27 {} as FormFieldContextValue,28)2930const FormField = <31 TFieldValues extends FieldValues = FieldValues,32 TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,33>({34 ...props35}: ControllerProps<TFieldValues, TName>) => {36 return (37 <FormFieldContext.Provider value={{ name: props.name }}>38 <Controller {...props} />39 </FormFieldContext.Provider>40 )41}4243const useFormField = () => {44 const fieldContext = React.useContext(FormFieldContext)45 const itemContext = React.useContext(FormItemContext)46 const { getFieldState } = useFormContext()47 const formState = useFormState({ name: fieldContext.name })48 const fieldState = getFieldState(fieldContext.name, formState)4950 if (!fieldContext) {51 throw new Error("useFormField should be used within <FormField>")52 }5354 const { id } = itemContext5556 return {57 id,58 name: fieldContext.name,59 formItemId: `${id}-form-item`,60 formDescriptionId: `${id}-form-item-description`,61 formMessageId: `${id}-form-item-message`,62 ...fieldState,63 }64}6566type FormItemContextValue = {67 id: string68}6970const FormItemContext = React.createContext<FormItemContextValue>(71 {} as FormItemContextValue,72)7374function FormItem({ className, ...props }: React.ComponentProps<"div">) {75 const id = React.useId()7677 return (78 <FormItemContext.Provider value={{ id }}>79 <div80 data-slot="form-item"81 className={cn("flex flex-col gap-1", className)}82 {...props}83 />84 </FormItemContext.Provider>85 )86}8788function FormLabel({89 className,90 ...props91}: React.ComponentProps<"label">) {92 const { error, formItemId } = useFormField()9394 return (95 <Label96 data-slot="form-label"97 data-error={!!error}98 className={cn("data-[error=true]:text-destructive", className)}99 htmlFor={formItemId}100 {...props}101 />102 )103}104105// … truncated
What it pulls in
npm packages
Other registry items
Files it writes
More from muffled-ui-registry
All 55 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Accordionaccordion | muffled-ui-registry | Components | Free | 2 deps | |
| Alertalert | muffled-ui-registry | Components | Free | 1 dep | |
| Alert Dialogalert-dialog | muffled-ui-registry | Components | Free | 1 dep | |
| Avataravatar | muffled-ui-registry | Components | Free | 1 dep | |
| Badgebadge | muffled-ui-registry | Components | Free | 2 deps | |
| Breadcrumbbreadcrumb | muffled-ui-registry | Components | Free | 2 deps | |
| Buttonbutton | muffled-ui-registry | Components | Free | 2 deps | |
| Button Groupbutton-group | muffled-ui-registry | Components | Free | 2 deps |
