Improvement: Use `Controller` in `react` package to simplify and decouple form field implementation
Problem
Many input fields across our UI packages are facing issues such as:
- Default values not showing
-
Selectcomponents not registering values properly -
undefinedvalues being returned
These issues are consistently resolved when using useController from React Hook Form (RHF) instead of the register method.
While trying to resolve these issues, I ended up using useController in many fields. https://github.com/adityacodepublic/autoform/tree/fix-bugs
Improvement Suggestion
Move to using Controller in the react package, in the AutoFormField component, instead of relying on register. This change would:
- Fix form behavior issues: Components behave as expected without bugs.
- Decouple UI lib. from RHF: The UI package becomes form-library-agnostic, avoiding peer dependency on RHF.
-
Simplify usage: Users don’t need to use
useControllermanually. - Extensible: Allows us to support other form libraries like TanStack Forms in the future with minimal changes.
Additional Context
- We are already using
useControllerinstead of register in many ui libs. - Since
Controllerwraps only theFieldComponentinsideAutoFormField, re-renders are scoped to just the FieldComponent. The outer AutoFormField or FieldWrapper does not re-render on controlled state changes.
return (
<FieldWrapper
label={getLabel(field)}
error={error}
id={fullPath}
field={field}
>
<Controller
name={fullPath}
disabled={field.fieldConfig?.inputProps?.disabled}
render={({ field: formField }) => (
<FieldComponent
label={getLabel(field)}
field={field}
value={value}
error={error}
id={fullPath}
key={fullPath}
path={path}
inputProps={{
error: error,
key: `${fullPath}-input`,
...field.fieldConfig?.inputProps,
...formField,
}}
/>
)}
/>
</FieldWrapper>
);
};
@vantezzen Let me know your thoughts — happy to help implement this if it looks good to you.
libs like tanstack forms use controlled by default https://tanstack.com/form/latest/docs/philosophy#controlled-is-cool
shadcn also uses Controller for forms https://ui.shadcn.com/docs/components/form
Sounds very interesting, would be good to solve all these issues with one fix! Feel free to move on with this
I initially tried using Controller, but it required maintaining a list of components (like array/object fields) that don’t need to be controlled to avoid unnecessary re-renders. Ideally, components should be able to decide whether they want to receive controlled state updates or not.
- Instead, I added a custom
useFieldhook that returns the necessary field methods and passed it to component via props. Components can opt-in only when needed, keeping it flexible and avoiding re-renders especially for object and array fields.
Ideally, users of this library should use
useControllerorControllerfrom React Hook Form to create custom components. However, for internal components—and to keep UI packages agnostic of the form library—we need to pass field methods as props. This also allows supporting other form libraries in the future (e.g., TanStack Forms). and also users can access it as it requires no name or other props as they come prefilled (easy to use)
-
Added support for
resolverin theAutoFormcomponent. This enables features liketriggerandformState.isValidto work correctly, which previously weren't working (added tests to validate it) and it now supports various validation and re-validation modes. In the core package, added areplaceValueutility to convert literal values toundefinedinstead of removing them. This is necessary for the resolver to work correctly as before and ensures proper focus behavior. (onSubmit data doesn't get affected) -
Added a custom focus function that ensures array field labels are focused when validation errors occur but no items are appended yet.
-
An optional
formprop has been added toAutoForm, allowing a form instance (created viacreateFormControl) to be passed in externally. This removes the need foronFormInitand makes it easier to use form methods outside the component. (also allows passing additionaluseFormprops via it like validation mode etc). -
In
AutoFormField, Added auseFieldErrorhook to reduce unnecessary re-renders when errors occur (e.g. duringonSubmit).
I’ve updated the @mantine package to work with all these changes, and its tests are passing.
Note: The form prop and useFieldError rely on features like createFormControl and subscribe, introduced in react-hook-form@^7.55.0. So the minimum RHF version needs to be bumped in affected packages.
Give it a try and let me know your thoughts https://github.com/adityacodepublic/autoform/tree/changes-addResolver
usage of new form prop
import { createForm } from "@autoform/react";
const Form = () => {
const form = createForm();
const schema = z.object({
name: z.string(),
email: z.string().email(),
});
const schemaProvider = new ZodProvider(schema);
return (
<>
<AutoForm
form={form}
schema={schemaProvider}
withSubmit
/>
<button onClick={()=> form.reset()}>Reset</button>
</>
);
};
I am facing same issue in wizard form when go back to prev step select,datepicker value disappear even after defaultvalues is in code.
let me know how can i fix this or i have to update package
Once this issue is resolved, we can release an update to fix this behavior. For now, please refer #180 and #182