Input adapter
To make integration with different UI libraries easier, you can use the formInputAdapters
object to register custom input adapters.
It is simple implementation of Adapter Pattern that allows you to transform the props passed to the hookform-input
component to match the expected format of the UI library or your actual components that you are using without unnessesary refactor or adjustments.
API
formInputAdapters
exposes a single method register
that accepts an object with the following properties:
key
- a unique key that identifies the adaptertransformFn
- a function that accepts the props passed to thehookform-input
component and the original props and returns the transformed props
There is preregistered adapter that is used by default - _default
. It cuts down some of the data that is passed from hookform-input
to the input component related to the field state and form state coming from the react-hook-form
library.
While most of the reusable components are using spread operator to pass the props to the input component it could be a problem spread a whole formState
object on the html tag.
Ignored props:
fieldState
- state of input which might be useful for some additional UI styles / validation logic. It contains:
type definition for the fieldState
object:
type ControllerFieldState = {
invalid: boolean;
isTouched: boolean;
isDirty: boolean;
isValidating: boolean;
error?: FieldError;
};
formState
- whole state of the form context that the input is rendered infield
- object containing all the input props eg.onChange
,name
Default adapater implementation
formInputAdapters.register({
key: "_default",
transformFn: ({ field, fieldState, formState, ...inputProps }) => inputProps,
});
Usage
For example if you are using a Material UI library - TextField
component receives slightly different props than hookform-input
provides.
We pass error
as a string meant to be used as an error message, but Material UI expects it a boolean and the message is passed additionally as a helperText
.
To make this work, we can register an adapter that transforms the props to match the expected format.
In current implementation to achieve autocomplete for adapterKey prop in your IDE you are required to declare global interface simultaneously with registering the adapter.
import { formInputAdapters } from "hookform-input";
type MuiTextFieldProps = Omit<FormInputForwardedProps, "error"> & {
error?: boolean;
helperText?: string;
};
declare global {
interface FormInputAdapterKeys {
"MUI-TextField": MuiTextFieldProps;
}
}
formInputAdapters.register({
key: "MUI-TextField",
transformFn: (props, originalProps) => ({
...props,
error: !!props.error,
helperText: props.error ?? originalProps?.description,
}),
});
Now, when you use the hookform-input
with the MUI-TextField
key, the props will be transformed to match the expected format.
import TextField from "@mui/material/TextField";
import { useForm } from "react-hook-form";
const Component = () => {
const form = useForm({
defaultValues: {
text: "some value",
},
});
const onSubmit = (data) => {
console.log(data);
};
return (
<form onSubmit={format.handleSubmit(onSubmit)}>
<FormInputBare
name="text"
input={TextField}
adapterKey="MUI-TextField"
control={form.control}
/>
<button type="submit">Submit</button>
</form>
);
};
registration of the adapter should be done out of the react scope, for example before component declaration.