From d168c9f72e4eae7597dd22e6272ed052527e30c7 Mon Sep 17 00:00:00 2001
From: 22mb <249426134+22mb@users.noreply.github.com>
Date: Sat, 29 Aug 2026 13:28:09 +0900
Subject: [PATCH] docs: document exact ancestor-path matching since 7.81.0
Since react-hook-form 7.81.0 (react-hook-form/react-hook-form#13553),
subscriptions with `exact: true` also fire when an ancestor path of the
subscribed name is updated. Changes to nested child paths still do not
notify with `exact: true`. Update the `exact` row in the useWatch,
useFormState, useController, Controller, Watch, FormState and subscribe
props tables accordingly, and show subscribe's default (`boolean = false`).
---
src/content/docs/usecontroller.mdx | 18 +++++++++---------
src/content/docs/usecontroller/controller.mdx | 2 +-
src/content/docs/useform/subscribe.mdx | 16 ++++++++--------
src/content/docs/useformstate.mdx | 12 ++++++------
src/content/docs/useformstate/formstate.mdx | 14 +++++++-------
src/content/docs/usewatch.mdx | 16 ++++++++--------
src/content/docs/usewatch/watch.mdx | 2 +-
7 files changed, 40 insertions(+), 40 deletions(-)
diff --git a/src/content/docs/usecontroller.mdx b/src/content/docs/usecontroller.mdx
index a38611da0..482084f04 100644
--- a/src/content/docs/usecontroller.mdx
+++ b/src/content/docs/usecontroller.mdx
@@ -24,15 +24,15 @@ This custom hook powers [`Controller`](/docs/usecontroller/controller). Addition
The following table contains information about the arguments for `useController`.
-| Name | Type | Required | Description |
-| ------------------ | ----------------------------------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| `name` | [FieldPath](/ts#FieldPath) | ✓ | Unique name of your input. Reactive — the controller re-subscribes when this prop changes, allowing dynamic field name switching. |
-| `control` | [Control](/ts#Control) | | [`control`](/docs/useform/control) object provided by invoking `useForm`. Optional when using `FormProvider`. |
-| `rules` | Object | | Validation rules in the same format for `register`, which includes: `required`, `min`, `max`, `minLength`, `maxLength`, `pattern`, `validate`.
`rules={{ required: true }}` |
-| `shouldUnregister` | boolean = false | | Input will be unregistered after unmount and defaultValues will be removed as well. **Note:** this prop should be avoided when using with `useFieldArray` as `unregister` function gets called after input unmount/remount and reorder. |
-| `disabled` | boolean = false | | `disabled` prop will be returned from `field` prop. Controlled input will be disabled and its value will be omitted from the submission data. |
-| `defaultValue` | unknown | | **Important:** Cannot apply `undefined` to `defaultValue` or `defaultValues` at `useForm`.
- You need to either set `defaultValue` at the field-level or `useForm`'s `defaultValues`. `undefined` is not a valid value. If you used `defaultValues` at `useForm`, skip using this prop.
- If your form will invoke `reset` with default values, you will need to provide `useForm` with `defaultValues`.
- If `field.value` is `undefined` on first render, the input starts out uncontrolled and React will warn when it later becomes controlled — always set `defaultValue`/`defaultValues` to avoid this.
|
-| `exact` | boolean = true | | This prop will enable an exact match for input name subscriptions, default to true. **Note:** this differs from [`useWatch`](/docs/usewatch) and [`useFormState`](/docs/useformstate), which both default `exact` to `false`. |
+| Name | Type | Required | Description |
+| ------------------ | ----------------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
+| `name` | [FieldPath](/ts#FieldPath) | ✓ | Unique name of your input. Reactive — the controller re-subscribes when this prop changes, allowing dynamic field name switching. |
+| `control` | [Control](/ts#Control) | | [`control`](/docs/useform/control) object provided by invoking `useForm`. Optional when using `FormProvider`. |
+| `rules` | Object | | Validation rules in the same format for `register`, which includes: `required`, `min`, `max`, `minLength`, `maxLength`, `pattern`, `validate`.
`rules={{ required: true }}` |
+| `shouldUnregister` | boolean = false | | Input will be unregistered after unmount and defaultValues will be removed as well. **Note:** this prop should be avoided when using with `useFieldArray` as `unregister` function gets called after input unmount/remount and reorder. |
+| `disabled` | boolean = false | | `disabled` prop will be returned from `field` prop. Controlled input will be disabled and its value will be omitted from the submission data. |
+| `defaultValue` | unknown | | **Important:** Cannot apply `undefined` to `defaultValue` or `defaultValues` at `useForm`.- You need to either set `defaultValue` at the field-level or `useForm`'s `defaultValues`. `undefined` is not a valid value. If you used `defaultValues` at `useForm`, skip using this prop.
- If your form will invoke `reset` with default values, you will need to provide `useForm` with `defaultValues`.
- If `field.value` is `undefined` on first render, the input starts out uncontrolled and React will warn when it later becomes controlled — always set `defaultValue`/`defaultValues` to avoid this.
|
+| `exact` | boolean = true | | This prop will enable an exact match for input name subscriptions, default to true. With `exact: true`, the field is also updated when one of its ancestor paths is set (for example, a field named `"users.0.name"` reflects `setValue("users.0", { name: "Jane" })`), but not when a nested child path of its value changes (for example, `setValue("users.0.name", "Jane")` does not update a field named `"users.0"`). Pass `exact: false` to also receive nested updates. **Note:** this differs from [`useWatch`](/docs/usewatch) and [`useFormState`](/docs/useformstate), which both default `exact` to `false`. |
### Return
diff --git a/src/content/docs/usecontroller/controller.mdx b/src/content/docs/usecontroller/controller.mdx
index 86d5de9db..d2624237f 100644
--- a/src/content/docs/usecontroller/controller.mdx
+++ b/src/content/docs/usecontroller/controller.mdx
@@ -26,7 +26,7 @@ The following table contains information about the arguments for `Controller`.
| `shouldUnregister` | boolean = false | | Input will be unregistered after unmount and defaultValues will be removed as well.
**Note:** this prop should be avoided when using with `useFieldArray` as `unregister` function gets called after input unmount/remount and reorder. |
| `disabled` | boolean = false | | `disabled` prop will be returned from `field` prop. Controlled input will be disabled and its value will be omitted from the submission data. |
| `defaultValue` | unknown | | **Important:** Cannot apply `undefined` to `defaultValue` or `defaultValues` at `useForm`. - You need to either set `defaultValue` at the field level or `useForm`'s `defaultValues`. If you used
defaultValues at useForm, skip using this prop. - If your form will invoke `reset` with default values, you will need to provide `useForm` with `defaultValues`.
- Calling `onChange` with `undefined` is not valid. You should use `null` or the empty string as your default/cleared value instead.
- If `field.value` is `undefined` on first render, the input starts out uncontrolled and React will warn when it later becomes controlled — always set `defaultValue`/`defaultValues` to avoid this.
|
-| `exact` | boolean = true | | This prop will enable an exact match for input name subscriptions, default to true. |
+| `exact` | boolean = true | | This prop will enable an exact match for input name subscriptions, default to true. With `exact: true`, the field is also updated when one of its ancestor paths is set, but not when a nested child path of its value changes. See [`useController`](/docs/usecontroller) for details. |
### Return
diff --git a/src/content/docs/useform/subscribe.mdx b/src/content/docs/useform/subscribe.mdx
index d544e5e85..84bed1c2b 100644
--- a/src/content/docs/useform/subscribe.mdx
+++ b/src/content/docs/useform/subscribe.mdx
@@ -13,14 +13,14 @@ Subscribe to [`formState`](/docs/useform/formstate) changes and value updates. Y
---
-| Name | Type | Description | Example |
-| --------- | --------------------------------------------- | ------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
-| name | undefined | Subscribe to the entire form | `subscribe()` |
-| | string | Subscribe to a single field by **name**. | `subscribe({ name: 'firstName' })` |
-| | string[] | Subscribe to multiple fields by **name**. | `subscribe({ name: ['firstName', 'lastName'] })` |
-| formState | `Partial` | Pick which [`formState`](/docs/useform/formstate) to subscribe to. | |
-| callback | `Function` | The callback function for the subscription. | { \n console.log(values) \n } \n})`}/> |
-| exact | boolean | This prop will enable an exact match for input name subscriptions. | `subscribe({ name: 'target', exact: true })` |
+| Name | Type | Description | Example |
+| --------- | --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
+| name | undefined | Subscribe to the entire form | `subscribe()` |
+| | string | Subscribe to a single field by **name**. | `subscribe({ name: 'firstName' })` |
+| | string[] | Subscribe to multiple fields by **name**. | `subscribe({ name: ['firstName', 'lastName'] })` |
+| formState | `Partial` | Pick which [`formState`](/docs/useform/formstate) to subscribe to. | |
+| callback | `Function` | The callback function for the subscription. | { \n console.log(values) \n } \n})`}/> |
+| exact | boolean = false | Enable exact name matching. When `false` (default), the subscription fires when the subscribed name is a prefix of the changed field name, or vice versa. When `true`, it fires when the subscribed field itself or one of its ancestor paths is updated, but not when a nested child path changes (for example, `"users.0.name"` is updated when `"users"` is set, while `"users"` is not updated when `"users.0.name"` changes). | `subscribe({ name: 'target', exact: true })` |
diff --git a/src/content/docs/useformstate.mdx b/src/content/docs/useformstate.mdx
index 160361307..0e46140b3 100644
--- a/src/content/docs/useformstate.mdx
+++ b/src/content/docs/useformstate.mdx
@@ -26,12 +26,12 @@ This custom hook allows you to subscribe to each form state, and isolate re-rend
---
-| Name | Type | Description |
-| ---------- | ---------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
-| `control` | Object | [`control`](/docs/useform/control) object provided by `useForm`. It's optional if you are using `FormProvider`. |
-| `name` | string \| string[] | Provide a single input name, an array of them, or subscribe to all inputs' formState updates. |
-| `disabled` | boolean = false | Option to disable the subscription. |
-| `exact` | boolean = false | This prop will enable an exact match for input name subscriptions. |
+| Name | Type | Description |
+| ---------- | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
+| `control` | Object | [`control`](/docs/useform/control) object provided by `useForm`. It's optional if you are using `FormProvider`. |
+| `name` | string \| string[] | Provide a single input name, an array of them, or subscribe to all inputs' formState updates. |
+| `disabled` | boolean = false | Option to disable the subscription. |
+| `exact` | boolean = false | Enable exact name matching. When `false` (default), a subscription fires when the subscribed name is a prefix of the changed field name, or vice versa (for example, subscribing to `"users"` receives updates for `"users.0.name"`). When `true`, the subscription fires when the subscribed field itself or one of its ancestor paths is updated (for example, subscribing to `"users.0.name"` receives updates when `"users.0"` or `"users"` is set via `setValue`), but not when a nested child path changes (subscribing to `"users"` does not receive updates for `"users.0.name"`). |
### Return
diff --git a/src/content/docs/useformstate/formstate.mdx b/src/content/docs/useformstate/formstate.mdx
index edea8cedd..2ac691346 100644
--- a/src/content/docs/useformstate/formstate.mdx
+++ b/src/content/docs/useformstate/formstate.mdx
@@ -13,13 +13,13 @@ A React Hook Form component that provides the same functionality as `useFormStat
---
-| Name | Type | Description |
-| ---------- | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| `control` | Object | [`control`](/docs/useform/control) object provided by `useForm`. It's optional if you are using `FormProvider`. |
-| `name` | string \| string[] | Provide a single input name, an array of them, or subscribe to all inputs' formState update. |
-| `disabled` | boolean = false | Option to disable the subscription. |
-| `exact` | boolean = false | This prop will enable an exact match for input name subscriptions. |
-| `render` | Function | Subscribes to form state of specified form field(s) and re-renders its child function whenever the form state changes. This allows you to declaratively consume form state in JSX without manually wiring up state. |
+| Name | Type | Description |
+| ---------- | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
+| `control` | Object | [`control`](/docs/useform/control) object provided by `useForm`. It's optional if you are using `FormProvider`. |
+| `name` | string \| string[] | Provide a single input name, an array of them, or subscribe to all inputs' formState update. |
+| `disabled` | boolean = false | Option to disable the subscription. |
+| `exact` | boolean = false | Enable exact name matching. When `false` (default), the subscription fires when the subscribed name is a prefix of the changed field name, or vice versa. When `true`, it fires when the subscribed field itself or one of its ancestor paths is updated, but not when a nested child path changes. See [`useFormState`](/docs/useformstate) for details. |
+| `render` | Function | Subscribes to form state of specified form field(s) and re-renders its child function whenever the form state changes. This allows you to declaratively consume form state in JSX without manually wiring up state. |
diff --git a/src/content/docs/usewatch.mdx b/src/content/docs/usewatch.mdx
index f6e1798de..f8b459c7b 100644
--- a/src/content/docs/usewatch.mdx
+++ b/src/content/docs/usewatch.mdx
@@ -22,14 +22,14 @@ Behaves similarly to the `watch` API; however, it isolates re-rendering at the c
---
-| Name | Type | Description |
-| -------------- | ---------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| `name` | string \| string[] \| undefined | Name of the field. Reactive — changing this prop dynamically will update the subscription to the new field name. |
-| `control` | Object | [`control`](/docs/useform/control) object provided by `useForm`. It's optional if you are using `FormProvider`. |
-| `compute` | function | Subscribe to selective and computed form values.
- Subscribe to the entire form but only return updated value with certain condition { \n if (data.test?.length) return data.test; \n\n return ''; \n }, \n});`}/>
- Subscribe to a specific form value state { \n return data.length ? data : ''; \n }, \n});`}/>
|
-| `defaultValue` | unknown | Fallback value returned before the form has mounted and no current value exists yet. Once the form is mounted, the actual current form value takes precedence over this fallback. |
-| `disabled` | boolean = false | Option to disable the subscription. |
-| `exact` | boolean = false | Enable exact name matching. When `false` (default), a subscription fires when the subscribed name is a prefix of the changed field name, or vice versa (for example, subscribing to `"users"` receives updates for `"users.0.name"`). |
+| Name | Type | Description |
+| -------------- | ---------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
+| `name` | string \| string[] \| undefined | Name of the field. Reactive — changing this prop dynamically will update the subscription to the new field name. |
+| `control` | Object | [`control`](/docs/useform/control) object provided by `useForm`. It's optional if you are using `FormProvider`. |
+| `compute` | function | Subscribe to selective and computed form values.
- Subscribe to the entire form but only return updated value with certain condition { \n if (data.test?.length) return data.test; \n\n return ''; \n }, \n});`}/>
- Subscribe to a specific form value state { \n return data.length ? data : ''; \n }, \n});`}/>
|
+| `defaultValue` | unknown | Fallback value returned before the form has mounted and no current value exists yet. Once the form is mounted, the actual current form value takes precedence over this fallback. |
+| `disabled` | boolean = false | Option to disable the subscription. |
+| `exact` | boolean = false | Enable exact name matching. When `false` (default), a subscription fires when the subscribed name is a prefix of the changed field name, or vice versa (for example, subscribing to `"users"` receives updates for `"users.0.name"`). When `true`, the subscription fires when the subscribed field itself or one of its ancestor paths is updated (for example, subscribing to `"users.0.name"` receives updates when `"users.0"` or `"users"` is set via `setValue`), but not when a nested child path changes (subscribing to `"users"` does not receive updates for `"users.0.name"`). |
### Return
diff --git a/src/content/docs/usewatch/watch.mdx b/src/content/docs/usewatch/watch.mdx
index 216ee79fb..dfb4f75fd 100644
--- a/src/content/docs/usewatch/watch.mdx
+++ b/src/content/docs/usewatch/watch.mdx
@@ -20,7 +20,7 @@ A React Hook Form component that provides the same functionality as `useWatch`,
| `compute` | function | Subscribe to selective and computed form values.
- Subscribe to the entire form but only return updated value with certain condition { \n if (data.test?.length) return data.test; \n\n return ''; \n }, \n});`}/>
- Subscribe to a specific form value state { \n return data.length ? data : ''; \n }, \n});`}/>
|
| `defaultValue` | unknown | Fallback value returned before the form has mounted and no current value exists yet. Once the form is mounted, the actual current form value takes precedence over this fallback. |
| `disabled` | boolean = false | Option to disable the subscription. |
-| `exact` | boolean = false | This prop will enable an exact match for input name subscriptions. |
+| `exact` | boolean = false | Enable exact name matching. When `false` (default), the subscription fires when the subscribed name is a prefix of the changed field name, or vice versa. When `true`, it fires when the subscribed field itself or one of its ancestor paths is updated, but not when a nested child path changes. See [`useWatch`](/docs/usewatch) for details. |
| `render` | Function | Subscribes to specified form field(s) and re-renders its child function whenever the values change. This allows you to declaratively consume form values in JSX without manually wiring up state. |
##### Examples: