react-hook-form-zodlisted
Install: claude install-skill vadimgaidai/react-feature-kit
# React Hook Form + Zod — repo quick reference
How forms are built **in my projects**. Canonical schema shape: [references/schemas.md](references/schemas.md). For anything this file does not cover, fetch the current upstream docs via the `context7` MCP server (`/react-hook-form/react-hook-form`, `/colinhacks/zod`) rather than guessing.
## Where things live
- Schema + inferred type → `model/schemas.ts` (FSD projects) or a `schemas.ts` colocated with the form (non-FSD projects): `export const fooSchema = z.object({...})` + `export type TFooFormValues = z.infer<typeof fooSchema>`. Never inline schemas in components or the API layer.
- Form component → `ui/[name]-form.tsx` (FSD) / `[name]-form.tsx`, one form per file. Submit target is a mutation hook from the module's mutations file.
## The form recipe
```tsx
const form = useForm<TFooFormValues>({
resolver: zodResolver(fooSchema),
defaultValues: { email: "", password: "" }, // ALWAYS provide — avoids uncontrolled→controlled warnings
})
```
- Layout: `FieldGroup` + `Field` + `FieldLabel` + `FieldDescription` — never raw `div`s, never legacy `Form`/`FormField`/`FormItem`. Array rows (tags, photo URLs) are still `Field`s.
- `register` for plain inputs; `Controller` for Select/Combobox/DatePicker.
- Errors via `FieldDescription` driven by `errors.[field]?.message`. Let RHF + Zod validate — no manual `onChange` validation.
- Submit button: `disabled={isSubmitting || mutation.isPending}` + `Spinner` with `data-icon="inline-st