Reusable Field component best practices #11939
-
so um I've been trying to make a reusable Input component so I don't have to copy paste all of the styles everywhere and I made this
But I feel like this is not the right way to do it or maybe it is at this point I don't know. if anyone has built a similar component I would appreciate help and suggestion |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 6 replies
-
Context: I've been using r-h-f for a couple years now in an enterprise app as someone who maintains reusable r-h-f stuff (like a clojure translation and reusable components) for less ui-experienced devs in the rest of our org. I'm actually going to soon construct almost exactly what you have there, error and label included, for our other common form field variations. I think you're 90% doing the right thing. First, some more subjective stuff: My first question is: will this stop at an If it's just for an HTMLInputElement, I'd probably still name this something different, as the term "Form Field" to me could mean any field in a form, that could use either of But these are subjective takes. If you intend to only ever have what your example shows, and just don't like my suggestions above, what I would at least do is just remove the Once your label/error/styling is standardized into whatever component or reusable code you like, you won't have to repeat much, except for What I'm doing in my org is the following:
|
Beta Was this translation helpful? Give feedback.
-
Another way is to use the Controller component in RHF to wrap your input component. import { ComponentPropsWithoutRef } from 'react';
import { Controller, ControllerProps, FieldPath, FieldValues, useForm } from 'react-hook-form';
type TextInputProps<
TFieldValues extends FieldValues = FieldValues,
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
> = Pick<ControllerProps<TFieldValues, TName>, 'name' | 'control' | 'rules'> &
ComponentPropsWithoutRef<'input'>;
function TextInput<T extends FieldValues = FieldValues, U extends FieldPath<T> = FieldPath<T>>({
name,
control,
rules,
onChange,
onBlur,
...rest
}: TextInputProps<T, U>) {
return (
<Controller
name={name}
rules={rules}
control={control}
render={({ field, fieldState }) => (
<div>
<input
{...rest}
{...field}
onBlur={(e) => {
field.onBlur();
onBlur?.(e);
}}
onChange={(e) => {
field.onChange(e);
onChange?.(e);
}}
/>
{fieldState.error && fieldState.error.message && <div>{fieldState.error.message}</div>}
</div>
)}
/>
);
} This allows you to use this component with type safety for field names. export function Form() {
const { control, handleSubmit } = useForm({
defaultValues: {
fieldName: '',
},
});
return (
<form onSubmit={handleSubmit((values) => console.log(values))}>
<TextInput
control={control}
name='fieldName'
rules={{ required: { value: true, message: 'Required' } }}
/>
<input type='submit' />
</form>
);
} |
Beta Was this translation helpful? Give feedback.
-
Check the third-party bindings section in the RHF documentation to learn more. |
Beta Was this translation helpful? Give feedback.
ok so this is how I rewrote the component