NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
npm · #750 most downloaded on npm
Performant, flexible and extensible forms library for React Hooks
Last release 8 days ago
26 Sep 2026
Ships on a steady schedule
a new release about every 2 weeks
Nearly every release is documented
notes for 60 of the last 60 stable releases
Nothing withdrawn
no release was ever pulled
8 years old
1100 releases · first in 2019
😭 close #7686 regression on replace API and cloneObject on payload
😭 close #7686 regression on replace API and cloneObject on payload (#7687)
⚛️ close #7683 support preact with onTouched mode
⚛️ close #7683 support preact with onTouched mode (#7684)
thanks to @Moshyfawn
One column per quarter.
🐞 fix #7662 issue with reset file input (#7656) 🚗 improve perf with get proxy formState (#7655) 🏋️ remove redundant check (#7651) 🐞 fix #7648 Unable t
🐞 fix #7662 issue with reset file input (#7656)
🚗 improve perf with get proxy formState (#7655)
🏋️ remove redundant check (#7651)
🐞 fix #7648 Unable to setFocus to Controller after reset (#7649)
🐞 fix: getFieldState - error might be undefined (#7636)
⛑ improve useFieldArray code consistency (#7628)
thanks to @Moshyfawn and @michalbundyra
✨ new getFieldState API: get individual field state
✨ new getFieldState API: get individual field state
Documentation: https://react-hook-form.com/api/useform/getfieldstate
import * as React from "react";
import { useForm } from "react-hook-form";
export default function App() {
const {
register,
getFieldState,
formState: { isDirty, isValid }
} = useForm({
mode: "onChange",
defaultValues: {
firstName: ""
}
});
// you can invoke before render or within the render function
const fieldState = getFieldState("firstName");
return (
<form>
<input {...register("firstName", { required: true })} />
<p>{getFieldState("firstName").isDirty && "dirty"}</p>
<p>{getFieldState("firstName").isTouched && "touched"}</p>
<button type="button" onClick={() => console.log(getFieldState("firstName"))}>
field state
</button>
</form>
);
}
😰 close #7593 regression on fieldarray controller/useController unmount with unregister (#7596) 🥸 fix type issue with getFieldState and useController
😰 close #7593 regression on fieldarray controller/useController unmount with unregister (#7596)
🥸 fix type issue with getFieldState and useController (#7574)
🖨 fix #7571 cloneObject with setValue passed argument (#7572) 🦺 unstable _getFieldState API for retrieve field level state (#7475) 💻 fix build on Wind
🖨 fix #7571 cloneObject with setValue passed argument (#7572)
🦺 unstable _getFieldState API for retrieve field level state (#7475)
💻 fix build on Windows (#7532)
thanks to @felixschorer
🧠 close #6425 memorise useController prop: onChange onBlur and ref (#7526) 📛 related #7521 include name check with resetField (#7521) 🪝 close #7518 ma
🧠 close #6425 memorise useController prop: onChange onBlur and ref (#7526)
📛 related #7521 include name check with resetField (#7521)
🪝 close #7518 making value update before custom onChange (#7519)
🐞 fix #7256 setValue with shouldDirty and shouldTouch combine not update state correctly (#7508)
useController return prop: onChange, onBlur and ref will be memorized with useCallback💻 Feature/avoid omitting key name use field array (improve DX) (#7301) ```tsx const App = () => { const { control, register, handleSubmit } = useForm
Happy new year 2022!
💻 Feature/avoid omitting key name use field array (improve DX) (#7301)
const App = () => {
const { control, register, handleSubmit } = useForm<FormValues>({
defaultValues: {
test: [{id: 'UUID5678', test: 'data' }] // id will be remained as it match default keyName
}
});
const { fields, append } = useFieldArray({
control,
name: 'test',
});
return (
<form>
{fields.map((field, index) => {
return <input key={field.id} {...register(`test.${index}.test`)} />;
})}
<button
type={'button'}
onClick={() => {
append({
id: 'UUID1234', // id value will be remained as it match default keyName
test: '1234',
});
}}
>
append
</button>
</form>
);
};
📲 apply useCallback for callback function to improve perf (#7378)
🐷 test coverage for types (#7311)
🐎 improve useFieldArray performance with separate id state (#7447)
🎩 close #6776 improve register to support shadow roots (#7400)
📇 fix type infer with UseFormHandleSubmit (#7405)
🎐 remove resolutions dep and update packages (#7396)
🎼 import type for utility
🥌 improve useFormState with mounted ref to skip update when hook is unmounted (#7489)
🪔 improve updateFieldArray batch update (#7477)
🪡 revert #6834 clearError should not affect isValid (#7470)
thanks to @daisuke85a, @MichalTarasiuk, @adrianos10, @barrymay and @felixschorer!
useFieldArray change keyName is no longer required when field value contains idconst App = () => {
const { control, register, handleSubmit } = useForm<FormValues>({
defaultValues: {
test: [{ id: 'UUID5678', test: 'data' }], // id value will be retained
},
});
const { fields, append } = useFieldArray({
control,
name: 'test',
});
return (
<form>
{fields.map((field, index) => {
return <input key={field.id} {...register(`test.${index}.test`)} />;
})}
<button
type={'button'}
onClick={() => {
append({
id: 'UUID1234', // id value will be retained
test: '1234',
});
}}
>
append
</button>
</form>
);
};
useFormState will no longer fire state update after hook unmountUseFormHandleSubmit type will infer formValues🐎 improve useFieldArray performance with separate id state (#7447) 🎩 close #6776 improve register to support shadow roots (#7400) 📇 fix type infer wit
🐎 improve useFieldArray performance with separate id state (#7447)
🎩 close #6776 improve register to support shadow roots (#7400)
📇 fix type infer with UseFormHandleSubmit (#7405)
🎐 remove resolutions dep and update packages (#7396)
🎼 import type for utility
thanks to @MichalTarasiuk, @adrianos10 and @felixschorer
💻 Feature/avoid omitting key name use field array (improve DX)
💻 Feature/avoid omitting key name use field array (improve DX) (#7301)
const App = () => {
const { control, register, handleSubmit } = useForm<FormValues>({
defaultValues: {
test: [{id: 'UUID5678', test: 'data' }] // id will be remained as it match default keyName
}
});
const { fields, append } = useFieldArray({
control,
name: 'test',
});
return (
<form>
{fields.map((field, index) => {
return <input key={field.id} {...register(`test.${index}.test`)} />;
})}
<button
type={'button'}
onClick={() => {
append({
id: 'UUID1234', // id value will be remained as it match default keyName
test: '1234',
});
}}
>
append
</button>
<button>submit</button>
</form>
);
};
📲 apply useCallback for callback function to improve perf (#7378) 🐷 test coverage for types (#7311)
thanks to @felixschorer
🎳 fix: change type order to make typescript hints for watch available (#7353) 🍂 close #7341 allow useWatch to fallback to defaultValue with undefined
🎳 fix: change type order to make typescript hints for watch available (#7353)
🍂 close #7341 allow useWatch to fallback to defaultValue with undefined (#7360)
🐞 fix #7347 defaultValues not populate with disabled input (#7359)
thanks to @pawk3k and @felixschorer
⚔️ close #7348 avoid errors state update with replace and update API (#7349) ⌨️ include UnpackNestedValue for reset values (#7286) ⌨️ close #7338 upda
⚔️ close #7348 avoid errors state update with replace and update API (#7349)
⌨️ include UnpackNestedValue for reset values (#7286)
⌨️ close #7338 update FieldNamesMarkedBoolean type to boolean instead of true (#7340)
😿 fix #7313 shouldUnregister prop with useController/controller after unmount
😿 fix #7313 shouldUnregister prop with useController/controller after unmount (#7317)
🐞 close #7293 with async useFieldArray reset
🐞 close #7293 with async useFieldArray reset (#7299)
🐞 fix #7282 async reset within onSubmit formState update
🐞 fix #7282 async reset within onSubmit formState update (#7285)
🖱️ improve dx with reset API within onSubmit or combined with other
🖱️ improve dx with reset API within onSubmit or combined with other (#7274)
const onSubmit = (data) => {};
React.useEffect(() => {
if (formState.isSubmitSuccessful) {
reset({ something: '' });
}
}, [formState, reset]);
handleSubmit(onSubmit);
to
const onSubmit = (data) => {
setSubmittedData(data);
reset(data); // no longer need to have useEffect
};
handleSubmit(onSubmit);
🐞 fix #7268 async reset API with useFieldArray (#7269) 🏛️ build(esm): Use explicit .mjs extension for ESM, with CJS interop (#7262)
huge thanks goes to @evocateur
reset provided with valueconst onSubmit = (data) => {};
React.useEffect(() => {
if (formState.isSubmitSuccessful) {
reset({ something: '' });
}
}, [formState, reset]);
handleSubmit(onSubmit);
to
const onSubmit = (data) => {
setSubmittedData(data);
reset(data); // no longer need to have useEffect
};
handleSubmit(onSubmit);
📏 beta: build(esm): Use explicit .mjs extension for ESM, with CJS interop
📏 beta: build(esm): Use explicit .mjs extension for ESM, with CJS interop
Revert "🏗️ build(esm): Use explicit .mjs extension for ESM (#7244)"
Revert "🏗️ build(esm): Use explicit .mjs extension for ESM (#7244)"
thanks to @evocateur
🪑 remove UnionLike type (#7187) 🌊 useFieldArray deep nested object issue due to object reference (#7240) 🏗️ build(esm): Use explicit .mjs extension fo
🪑 remove UnionLike type (#7187) 🌊 useFieldArray deep nested object issue due to object reference (#7240) 🏗️ build(esm): Use explicit .mjs extension for ESM (#7244) 🎮 close #7231 set deep nested value with controlled input via setValue (#7232)
thanks to @evocateur
Nothing published for this version
📏 shouldUseNativeValidation will inject native validation attributes into field which supports both client & server
📏 shouldUseNativeValidation will inject native validation attributes into field which supports both client & server (#7207)
const { register } = useForm()
<input {...register('name', { required: true })} />
<input name="name" required /> // both client and server render
🤦🏻♂️ fix #2717 regression with async field array actions (#7218)
shouldUseNativeValidation will pass down validation props both at client and server renderconst { register } = useForm()
<input {...register('name', { required: true })} />
<input name="name" required /> // both client and server render
🐞 fix #7174 issue with empty errors object prevent submit
🐞 fix #7174 issue with empty errors object prevent submit
Revert 🔢 fix #7149 Supporting Number Object comparison in deepEqual
Revert 🔢 fix #7149 Supporting Number Object comparison in deepEqual (#7150)
thanks to @barrymay
…prevent update input type with files (#7147) ✂️ deprecate unset empty array function (#7120) 🐞 fix #7109 issue with field array dirty fields
👩👩👧👧 unify register onChange with useController retrieve value (#7153)
👍 fix setCustomValidity typo (#7154)
🔢 fix #7149 Supporting Number Object comparison in deepEqual (#7150)
🙅 prevent update input type with files (#7147)
✂️ deprecate unset empty array function (#7120)
🐞 fix #7109 issue with field array dirty fields (#7119)
thanks to @getTobiasNielsen @swapnilrohom @lxy-yz and @LucasLemanowicz
onChange will share same logic with useController for non standard event payloadconst { onChange } = register('test');
onChange('stringIsValid'); // this is only valid use case for JS
formState will no longer gets unset🐞 fix #7090 shallow clone for object has no prototype methods (#7096) 😮💨 revert module config (#7095) 📦 change node engine to >= 12.0
🐞 fix #7090 shallow clone for object has no prototype methods (#7096) 😮💨 revert module config (#7095) 📦 change node engine to >= 12.0
thanks to @barrymay
🥃 revert #7016 and add type test coverage (#7082) 🫀 close #7079 flush update at the field array level before app/form-level
🥃 revert #7016 and add type test coverage (#7082) 🫀 close #7079 flush update at the field array level before app/form-level (#7080)
✨ feature: useWatch/useFormState exact prop (#6983) ```tsx useWatch({ name: 'test.test', exact: true, });
✨ feature: useWatch/useFormState exact prop (#6983)
useWatch({
name: 'test.test',
exact: true,
});
useFormState({
name: 'test.test',
exact: true,
});
🎳 close #7032 with stale onBlur value (#7078) 📦 upgrade to ts 4.5.2 (#6944) 👂 remove early subscription (#7056) 📦 chore: Modify package.json to include es6 imports (#7034) 🗃️ fix(package.json): add node requirement version (#7039)
thanks to @barrymay @neighborhood999 and @karanaditya993
exact prop for useWatchexact prop for useFormStateuseWatch({
name: 'test.test',
exact: true,
});
useFormState({
name: 'test.test',
exact: true,
});
useWatch subscription will occurred at useEffect instead before render🐞 fix #7031 fast refresh
🐞 fix #7031 fast refresh (#7035)
💅 close #7023 issue with async useFieldArray actions (#7029) 👁️ chore(useWatch): making the name a read-only array (#7016) ⌨️ adds types for no suppli
💅 close #7023 issue with async useFieldArray actions (#7029) 👁️ chore(useWatch): making the name a read-only array (#7016) ⌨️ adds types for no supplied props argument (#7017) 🤦🏻♂️ close #7013 avoid shallow clone for the custom object (#7014)
thanks to @dborysov @sfrieson
🐞 fix #7011 reset API with shouldUnregister: true for controlled components
🐞 fix #7011 reset API with shouldUnregister: true for controlled components (#7012)
🐞 fix #7009 fix fast refresh with controller (#7010) 👍🏻 close #7001 shouldUnregister: true with useController unmount defaultValue (#7008) 🧠 close #69
🐞 fix #7009 fix fast refresh with controller (#7010) 👍🏻 close #7001 shouldUnregister: true with useController unmount defaultValue (#7008) 🧠 close #6994 issue with mutate original state with shouldUnreigster: true (#6998)
🐞 fix #6984 disabled input with register value (#6985) 🤲 close #6987 avoid shallow clone for object field
🐞 fix #6984 disabled input with register value (#6985) 🤲 close #6987 avoid shallow clone for object field (#6988)
```tsx const { resetField } = useForm();
✨ feature: new resetField API (#6891)
const { resetField } = useForm();
resetField('test')
resetField('test', {
keepError: true,
keepDirty: true,
keepTouched: true,
defaultValue: 'test1',
})
⏱ close #6966 improve trigger by avoiding additional validation invocation (#6967)
thanks to @barrymay and @kotarella1110
resetField APIconst { resetField } = useForm();
resetField('test');
resetField('test', {
keepError: true,
keepDirty: true,
keepTouched: true,
defaultValue: 'test1',
});
useController will return shallow clone value for the following data type on each rerender
{... value}[...value]```tsx const { resetField } = useForm();
✨ new resetField API
const { resetField } = useForm();
resetField('test')
resetField('test', {
keepError: true,
keepDirty: true,
keepTouched: true,
defaultValue: 'test1',
})
🧢 close #6928 prevent schema error before user's action (#6929)
🧹remove createSubscription and createSubscriber to reduce size (#6880)
✌🏻 improve react strict mode support with subscription
✌🏻 improve useController by integrating with useWatch
✌🏻 package size-reduction (close to 1%)
✌🏻 internally removed skipEarlySubscription
😔 fix 6933 by revert FieldPathWithValue type #6753 (#6934) 🧢 close #6928 prevent schema error before user's action
😔 fix 6933 by revert FieldPathWithValue type #6753 (#6934)
🧢 close #6928 prevent schema error before user's action (#6929)
thanks to @mnigh @kotarella1110 @barrymay
👨👨👦 schema error parent level look up
👨👨👦 schema error parent level look up (#6869)
const validationSchema = object().shape({
questions: array()
.min(1, "Array cannot be empty")
.of(
object().shape({
text: string().required("Some text is required")
})
)
});
function App() {
const {
control,
formState: { errors },
register
} = useForm({
mode: "onChange",
resolver: yupResolver(validationSchema),
defaultValues: { questions: [ { text: 'test' } ] }
});
const { fields, remove } = useFieldArray({
control,
name: "questions",
});
console.log(errors);
return (
<form>
{fields.map((question, questionIndex) => (
<div key={question.key}>
<input {...register(`questions[${questionIndex}].text`)} />
<button type="button"
onClick={() => {
remove(questionIndex);
}}
>
Remove
</button>
</div>
))}
</form>
);
}
Codesandbox LInk: works with min length parent error object look up
😞 fix #6896 validation isValid mixed with schema result (#6901)
🍨 close #6899 trigger isolate render for targeted input name (#6900)
👂 close #6889 disable early subscription with useController (#6890)
🐞 fix #6792 reset with keepDefaultValues (#6886)
℁ change the subject from class to function base to improve readability and reduce the size (#6843)
👂🏻 make sure subscriptions get unsubscribed after unmount (#6873)
🧻 prevent error lookup with fields (#6871)
Revert "Revert "✨ Add support for generic components using `FieldPat… (#6753)
type ExpectedType = { test: string };
const Generic = <FormValues extends FieldValues>({
name,
control,
}: {
name: FieldPathWithValue<FormValues, ExpectedType>;
control: Control<FormValues>;
}) => {
const {
field: { value, ...fieldProps },
} = useController<FormValues, ExpectedType>({
name,
control,
defaultValue: { test: 'value' },
});
return <input type="text" value={value.test} {...fieldProps} />;
};
😢 fix #6856 regression on set input file list (#6861) ⌨️ fix #6852 watch missing type with DeepPartial (#6854)
thanks to @kotarella1110
FieldPathWithValueconst validationSchema = object().shape({
questions: array().min(1, 'Array cannot be empty'),
});
// the above schema will be picked up by field array action
// the logic applies to group error object eg checkboxes
<button
type="button"
onClick={() => {
remove(questionIndex);
}}
>
Remove
</button>;
✨ Add support for generic components using FieldPathWithValue
✨ Add support for generic components using FieldPathWithValue (#6562)
type ExpectedType = { test: string };
const Generic = <FormValues extends FieldValues>({
name,
control,
}: {
name: FieldPathWithValue<FormValues, ExpectedType>;
control: Control<FormValues>;
}) => {
const {
field: { value, ...fieldProps },
} = useController<FormValues, ExpectedType>({
name,
control,
defaultValue: { test: 'value' },
});
return <input type="text" value={value.test} {...fieldProps} />;
};
✨ enable sharing form sections between forms in typescript (#6807) 🐞 fix #6834 clearErrors not reset isValid formState to true ⚠️ close #6830 warning
✨ enable sharing form sections between forms in typescript (#6807)
🐞 fix #6834 clearErrors not reset isValid formState to true
⚠️ close #6830 warning under strict mode with Controller formState update (#6832)
🧪 include test coverage #6826 (#6827)
✨ add TypeScript support for optional array fields (#6826)
👔 allow Jest VSCode extension to run successfully on startup (#6810)
thanks to @barrymay @LinusU and @SimonSelg
😮💨 fix setFocus api issue #6804 ⌨️ close #6761 improve useWatch return array type (#6788) Revert "🧶 add support for extended generics in path type (#
😮💨 fix setFocus api issue #6804
⌨️ close #6761 improve useWatch return array type (#6788)
Revert "🧶 add support for extended generics in path type (#6762)" (#6802)
🐞 fix #6792 reset keep defaultValues with useWatch return (#6794)
⚡️ upgrade eslint to 8.0 and other package (#6789)
🦗 close #6777 fall back to defaultValues with shouldUnregister: true with unmount fieldArray (#6780) 🧯 change validation message in example code to ma
🦗 close #6777 fall back to defaultValues with shouldUnregister: true with unmount fieldArray (#6780)
🧯 change validation message in example code to match the rule better (#6781)
🌳 rename document.contains to live function (#6778)
🐞 fix 6764 reset with keepDefaultValues: true with isDirty and dirtyFields (#6774)
🐞 fix #6765 useFieldArray trigger validation by field name (#6768)
🧶 add support for extended generics in path type (#6762)
🐞 fix #6754 focus issue with radio and checkbox (#6755)
thanks to @RolkerMan @hpohlmeyer
🐞 fix #6748 skip clone object when object contains function nodes (#6749) ⏮ revert interface & mapped type update (#6747) 🐞 fix #6736 custom onChange
🐞 fix #6748 skip clone object when object contains function nodes (#6749) ⏮ revert interface & mapped type update (#6747) 🐞 fix #6736 custom onChange getting called on blur (#6746) 🐞 fix #6731 subscription issue with unmount field array (#6732) 💉 simplify controller field state error type (#6730) 🌟 improve reset with keepDefaultValues options (#6720) 👂 improve useSubscribe hook (#6724) 📖 more TS test coverage for missing generic at useForm (#6716)
thanks to @fzkirablackwhy @kotarella1110
Revert "✨ Add support for generic components using FieldPathWithValue (#6562)" (#6717) 🖌️ fix Path and ArrayPath types for defined value type with int
Revert "✨ Add support for generic components using FieldPathWithValue (#6562)" (#6717)
🖌️ fix Path and ArrayPath types for defined value type with interface (#6626)
🧉 close #6657 support equality check on date time object (#6706)
thanks to @kotarella1110 @jviall
✨ Add support for generic components using FieldPathWithValue
✨ Add support for generic components using FieldPathWithValue (#6562)
type ExpectedType = { test: string };
const Generic = <FormValues extends FieldValues>({
name,
control,
}: {
name: FieldPathWithValue<FormValues, ExpectedType>;
control: Control<FormValues>;
}) => {
const {
field: { value, ...fieldProps },
} = useController<FormValues, ExpectedType>({
name,
control,
defaultValue: { test: 'value' },
});
return <input type="text" value={value.test} {...fieldProps} />;
};
⚙️ migrate from Select.options to Select.selectedOptions (#6678) (#6687) 🐞 fix #6683 trigger regression with isValid subscription (#6686)
Thanks to @julienfouilhe and @krnlde
FieldPathWithValue to improve generic components type supporttype ExpectedType = { test: string };
const Generic = <FormValues extends FieldValues>({
name,
control,
}: {
name: FieldPathWithValue<FormValues, ExpectedType>;
control: Control<FormValues>;
}) => {
const {
field: { value, ...fieldProps },
} = useController<FormValues, ExpectedType>({
name,
control,
defaultValue: { test: 'value' },
});
return <input type="text" value={value.test} {...fieldProps} />;
};
⌨️ fix field state error type with NestedValue (#6658) 👓 fix #6655 issue with field array focus name with filter operator (#6656) 🐞 fix #6651 trigger
⌨️ fix field state error type with NestedValue (#6658) 👓 fix #6655 issue with field array focus name with filter operator (#6656) 🐞 fix #6651 trigger api with schema validation per field level (#6652)
Thanks to @kotarella1110 @barrymay @nicholascm @fahadsohail482
🎹 fix #6646 incorrect type with fieldState error (#6650) 🎧 refactor subscription logic into useSubscribe
🎹 fix #6646 incorrect type with fieldState error (#6650) 🎧 refactor subscription logic into useSubscribe (#6614)
Thanks to @kotarella1110 @barrymay
formState subscription no longer subscribed at useEffect instead the execution of each hook🪄 feat: Ability to provide custom onBlur and onChange handlers
🪄 feat: Ability to provide custom onBlur and onChange handlers (#5620)
<input
type="text"
{...register('test', {
onChange: (e) => {},
onBlur: (e) => {},
})}
/>
🗺️ fix Mapped types for defined value type with interface (#6605)
🏥 close #6590 prevent error throw by missing input with trigger API (#6591)
Thanks to @kotarella1110 @exneval @michalbundyra
register allowed pass custom onChange and onBlur<input
type="text"
{...register('test', {
onChange: (e) => {},
onBlur: (e) => {},
})}
/>
👨🏭 close #6581 by register input with setValue to improve DX for missing registered inputs (#6582) 💉 include unit test for #6581 setValue with missin
👨🏭 close #6581 by register input with setValue to improve DX for missing registered inputs (#6582) 💉 include unit test for #6581 setValue with missing input 🐞 fix #6573 calling setValue from useEffect at mount does not update controller value (#6578) ⌚️ close #6548 watch, reset with shouldUnregister: true by trigger extra re-render to flush out the current form values (#6549) 🐞 fix async useFieldArray actions (#6540) 🔖 fix typos in examples and source code (#6531) 💉 replace updateValues with cloneObject (#6530)
Thanks, @frankie303
🐞 fix #6528 async reset update isMounted when isValid is not subscribed (#6529) 🐞 fix #6513 reset config keepValues update formValues (#6524) 🐞 fix #6
🐞 fix #6528 async reset update isMounted when isValid is not subscribed (#6529)
🐞 fix #6513 reset config keepValues update formValues (#6524)
🐞 fix #6482 reset formValues with shouldUnregister: true (#6512)
🐞 fix #6509 return defaultValues when components are not mounted (#6511)
🔨 proper fix for useController default value update (#6510)
🐞 fix #2655 disabled input should set to undefined (#6501) 🐞 improve ControllerFieldState type for Controller types (#6500) 🐞 add File and FileList in
🐞 fix #2655 disabled input should set to undefined (#6501) 🐞 improve ControllerFieldState type for Controller types (#6500) 🐞 add File and FileList interface for ReactNative (#6495)
Thanks, @kotarella1110
Nothing published for this version
🚀 fix: add UnionLike type for FieldErrors and FieldNamesMarkedBoolean type (#6381) 💻 ci: update from ubuntu-16.04 to ubuntu-latest (#6485) 🐞 fix handl
🚀 fix: add UnionLike type for FieldErrors and FieldNamesMarkedBoolean type (#6381) 💻 ci: update from ubuntu-16.04 to ubuntu-latest (#6485) 🐞 fix handleChange to set undefined value (#6481) 🐞 fix #6473 isMount flag for useWatch value subscription (#6474) 🐞 fix #6469 schema checkbox validation incorrect parent node lookup (#6471)
🎇 [useFieldArray] new method replace()
🎇 [useFieldArray] new method replace() (#6304)
const { control } = useForm({
defaultValues: {
test: [{ value: 'lorem' }, { value: 'ipsum' }]
}
});
const { fields, replace } = useFieldArray({
control,
name: 'test'
});
const handleFullyReplacement = (): void => {
// remove old and set fully new values
replace([{ value: 'dolor' }, { value: 'sit' }, { value: 'amet' }]);
}
🐞 fix #6379 toggle disabled props with register api (#6459) 🗺️ improve Mapped types (#6451) 🗝️ refactor: improve NestedValue type (#6449) 🗝️ feat: improve PathValue type to fully support union type (#6431)
useFieldArray new method replace()const { control } = useForm({
defaultValues: {
test: [{ value: 'lorem' }, { value: 'ipsum' }],
},
});
const { fields, replace } = useFieldArray({
control,
name: 'test',
});
const handleFullyReplacement = (): void => {
// remove old and set fully new values
replace([{ value: 'dolor' }, { value: 'sit' }, { value: 'amet' }]);
};
interface.import { useForm } from 'react-hook-form';
interface CustomValue {
custom: string;
}
type FormValues = {
fieldName: CustomValue;
};
const { formState: errors } = useForm<FormValues>({
defaultValues: { fieldName: { custom: 'value' } },
});
🔑 fix: add UnionLike type for FieldErrors type #6381
🔑 fix: add UnionLike type for FieldErrors type #6381
🐛 fix #6403 issue with fields object with getter and setter function (#6407) ⌨️ update watch observer types (#6404) 🧥 fix getter and setter consistenc
🐛 fix #6403 issue with fields object with getter and setter function (#6407) ⌨️ update watch observer types (#6404) 🧥 fix getter and setter consistency (#6408)
👾 improve change event perf (#6373) 🐞 fix #6379 when disabled is not return from the DOM attribute (#6380) 🧻 code improvement and size reduction (#637
👾 improve change event perf (#6373) 🐞 fix #6379 when disabled is not return from the DOM attribute (#6380) 🧻 code improvement and size reduction (#6372) 🎮 prevent controller with TypeError: e.focus is not a function (#6386) Revert "🎹 fix #6265 objects may have error messages (#6275)" (#6391)
🥳 feature: add dependent validation - run a dependent field's validation after another field's validation runs
🥳 feature: add dependent validation - run a dependent field's validation after another field's validation runs (#6141)
const App = () => {
const { register, getValues } = useForm();
return (
<form>
<input
{...register('firstName', {
validate: (value) => {
return getValues('lastName') === value;
}
})}
/>
<input {...register('lastName', { deps: ['firstName'] })} /> // dependant validation
</form>
);
};
🦆 close #6319 remove shallow clone with watch return value (#6336) 🗝️ fix #6320 type issue with provider context (#6326) 🎛️ fix #6335 useController only update field ref #6341 🎮 close #6328 useController set defaultValue to be part of formValues (#6329) 📭 close #6367 missing absent empty object and array input from defaultValues (#6368)
register add dependent validationconst App = () => {
const { register, getValues } = useForm();
return (
<form>
<input
{...register('firstName', {
validate: (value) => {
return getValues('lastName') === value;
},
})}
/>
<input {...register('lastName', { deps: ['firstName'] })} /> // dependant
validation
</form>
);
};
🥳 feature: add dependent validation - run a dependent field's validation after another field's validation runs
🥳 feature: add dependent validation - run a dependent field's validation after another field's validation runs (#6141)
const App = () => {
const { register, getValues } = useForm();
return (
<form>
<input
{...register('firstName', {
validate: (value) => {
return getValues('lastName') === value;
}
})}
/>
<input {...register('lastName', { deps: ['firstName'] })} /> // dependant validation
</form>
);
};
🦆 close #6319 remove shallow clone with watch return value (#6336) 🗝️ fix #6320 type issue with provider context (#6326) 🎛️ fix #6335 useController only update field ref #6341 🎮 close #6328 useController set defaultValue to be part of formValues (#6329)
🏎 Performance enhancement at scale
🏎 Performance enhancement at scale
React hook from is getting a general performance upgrade and enhancement. The following API will get big performance improvement at scale, which means it may not improve on small or medium-size applications, but rather large and complex applications with subscriptions.
useWatchuseFieldArraywatchgetValuesResult Env: dev build + throttle 4x CPU + Chrome + MAC M1
| Version | Flat (1000) | Nested (1000) | Deeply Nested (1000 * 2 * 2000) | Flat (1000) Mount |
|---|---|---|---|---|
7.13.0-next.0 |
18ms | 20ms | 200ms | 470ms (no change) |
7.11.1 |
40ms | 43ms | 2000ms | 470ms |
📦 Package size-reduction
Total Size: 30.3 kB
| Filename | Size | Change | |
|---|---|---|---|
dist/index.cjs.js |
8.39 kB | -445 B (5%) | ✅ |
dist/index.esm.js |
13.4 kB | -656 B (4%) | |
dist/index.umd.js |
8.52 kB | -420 B (4%) |
🔫 Trigger
useFieldArray({ name: 'test' })
trigger('name') // will trigger the whole field array to validate
📑 register
disabled prop as an option to toggle input disable attributeref callbackregister('test', { disabled: true }) // will set value to undeinfed and pass disabled down to the input attribute
<div {...register('test')}>
<input name="test" /> // this input will be registered
</div>
👀 useWatch
disabled prop to toggle the state subscription.useWatch({ disabled: true }) // you toggle the subscription
⌨️ useFormState
disabled prop to toggle the state subscription.useFormState({ disabled: true }) // you toggle the subscription
⛳️ setValue
<input {...register('test.0.firstName')} />
setValue('test', [{ firstName: 'bill' }, {firstName: 'kotaro}, {firstName: 'joris'}]) // this will works
⏱️ close #6296 abort validation early when disable prop is detected (#6300) 🎹 fix #6265 objects may have error messages (#6275) 🔄 fix #6277 track async validate to trigger state update (#6284) 🐞 fix #6272 only flush field array when subscription name match (#6281) 💪🏻 simplify fillEmptyArray and combine focus name (#6237) 🌵 remove redundant code for useFieldArray (#6236) 🐞 patch remove, update api with key id persist (#6235) 🐞 close #6233 for persist field array id (#6234) 🍄 enable detect fields unmount at useWatch level (#6226) 💨 improve useFieldArray perf (#6215) 🍨 close #6193 to remove shallow merge with defaultValue with watch (#6201) 🐞 fix #6186 delayError with set error after delay (#6188) ☄️ enhance unregister unmount inputs by combining its logic (#6185) 🖨️ include reset clone value for array/object/date (#6183) 👨🏻🔧 fix rendering order with useFieldArray (#6182) 🎭 skip the shallow clone with useForm return (#6154) ⌨️ fix: WatchObserver info name type (#6171)
🐞 patch remove, update API with key id persist
🐞 patch remove, update API with key id persist (#6235)
🐞 close #6233 for persist field array id (#6234) 🍄 enable detect fields unmount at useWatch level
🐞 close #6233 for persist field array id (#6234) 🍄 enable detect fields unmount at useWatch level (#6226)
Your coding agent can read these notes before it upgrades. Set up the MCP server →