Install any skill in seconds. Free to start, no credit card required.
Get Started Free →supabase/react-hook-form
Correct React Hook Form usage anywhere in the monorepo — data flow, subscriptions, reset, dirty state, number inputs, and controlled-input rules. Load this BEFORE writing or modifying ANY form code, adding a field to an existing form, touching watch/useWatch/formState/getValues/setValue/reset, wiring a form into a dialog or sheet, or building a submit/cancel footer — even when the change looks trivial. The codebase contains widespread RHF anti-patterns; without this skill you will copy them. For
Passed 20 of 22 test cases with the skill, and 15 of 22 without it.
and 6 more in the full report
5 fixed15 passed either way2 still failing0 broke
Tokens, turns and time describe resource use, not a dollar price.
One of 5 test cases the skill fixed. Same model, same prompt, with and without the skill.
We need to log form value changes to an analytics provider without causing extra component re-renders. A developer wrote `form.watch((value) => sendAnalytics(value))` inside the component body. What is the correct API for render-free subscription listeners in React Hook Form?
| Checked | Without skill | With skill |
|---|---|---|
| Uses subscribe instead of watch for render-free listener callbacks. | Missed | Passed |
| Returns the cleanup function from subscribe inside a useEffect hook. | Missed | Passed |
The instructions your model reads when the skill loads.
How to write forms that stay correct as they grow. The existing codebase is not
a safe reference: form.watch() off prop-drilled form objects, subscription-only
watches, unguarded valueAsNumber, and ?? undefined controlled values are all
common in older code and all wrong. Follow this skill, not the neighboring file.
Policy — fix what you touch. New code must follow these rules. When you modify
existing form code, upgrade the specific fields/hooks/components you're editing to
match (e.g. a component you touch that calls form.watch gets converted to
useWatch). Leave untouched code alone, but tell the user about anti-patterns you
noticed and didn't fix. Never add new violations: react-hook-form/no-use-watch
is ratcheted in Studio CI — any increase in the warning count fails the build.
RHF is uncontrolled at heart. Values live in refs; nothing re-renders unless a subscription says so. Every read API is a subscription decision:
| API | Subscribes | Re-renders | Use for |
|---|---|---|---|
useWatch({ control, name }) | yes | only the calling component | reactive value reads, anywhere |
useFormState({ control }) | yes | only the calling component | isDirty/errors/etc. outside the form owner |
formState (destructured) | yes | the useForm owner | form state in the owner component only |
form.watch(name) | yes | the entire form tree | avoid — lint-flagged, see below |
getValues() | no | never | event handlers and onSubmit only |
subscribe() | callback | none | side effects outside render |
Two facts explain most of the bugs we've shipped:
form.watch() and form.formState hoist their subscription to the useForm
owner, no matter which component calls them. A child that reads
form.watch('x') off a prop works today only because the whole tree re-renders
on every change — it silently goes stale the moment anyone adds React.memo
between owner and child, and until then it re-renders every sibling on every
keystroke. A no-arg form.watch() sets watchAll and re-renders the tree on
every field change for the life of the form.formState is a Proxy — reading a property is what arms the subscription.
Destructure it (const { isDirty } = form.formState), never pass the object
around or read it conditionally (a && formState.isValid may never subscribe).test cases passed, vs 15 / 22 without
More skills from the same source and nearby in the registry, with their headline benchmark lift.