react hook form controller component that returns useController, or register return based on controlled boolean prop (default: true )
requires your form wrapped in FormProvider
import type {
FieldPath,
FieldValues,
ControllerProps,
UseControllerProps,
UseFormRegisterReturn,
ControllerRenderProps,
} from "react-hook-form";
import { useController, useFormContext } from "react-hook-form";
type ControlledProps<
TFieldValues extends FieldValues,
TName extends FieldPath<TFieldValues>,
TTransformedValues,
> = {
controlled: true;
} & ControllerProps<TFieldValues, TName, TTransformedValues>;
type UncontrolledProps<
TFieldValues extends FieldValues,
TName extends FieldPath<TFieldValues>,
TTransformedValues,
> = {
controlled: false;
render: ({
field,
}: {
field: UseFormRegisterReturn<TName>;
}) => React.ReactNode;
} & UseControllerProps<TFieldValues, TName, TTransformedValues>;
// Unified type
type CustomControllerProps<
TFieldValues extends FieldValues,
TName extends FieldPath<TFieldValues>,
TTransformedValues,
> =
| ControlledProps<TFieldValues, TName, TTransformedValues>
| UncontrolledProps<TFieldValues, TName, TTransformedValues>;
type renderField<
TFieldValues extends FieldValues,
TName extends FieldPath<TFieldValues>,
> = UseFormRegisterReturn<TName> | ControllerRenderProps<TFieldValues, TName>;
function Controller<
TFieldValues extends FieldValues = FieldValues,
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
TTransformedValues = TFieldValues,
>(props: CustomControllerProps<TFieldValues, TName, TTransformedValues>) {
const { register } = useFormContext<TFieldValues>();
if (props.controlled === false) {
return props.render({ field: register(props.name, props.rules) });
}
return props.render(
useController<TFieldValues, TName, TTransformedValues>(props)
);
}
export { Controller, type renderField };