Controlled TextFields with React-Hook-Form

Written on 2023-04-27 by Adam Drake - 4 min read

Image of Controlled TextFields with React-Hook-Form

On most apps I build nowadays there is a requirement to gather some user input and this requires a form to work with. There are a great number of things going on in forms and being able to handle that form state easily is a great advantage when developing. This is where react-hook-form really shines for me.

I am a big fan of react-hook-form and use it on many applications I work on. I am also a fan of using component libraries such as Material-UI, Chakra-ui or more recently Mantine.dev. In my opinion there isn't a huge difference in each of these and it more comes down to little design decisions and what is required in the app I am working on. (I realise some developers in the community are very vocal about building your own ui components but when you have business breathing down you neck to get an MVP (Minimal Viable Product) built, you really don't have time to worry about shadings on a button.)

I realise some developers in the community are very vocal about building your own ui components but when you have business breathing down you neck to get an MVP (Minimal Viable Product) built, you really don't have time to worry about shadings on a button.

I won't get into the ins and outs of how to use react-hook-form, if you want to see that then you can check out their docs. I want to focus on working with react-hook-form with a Component library and in this blog post I will be using Mantine.dev.

Controlled Text Fields

In any react application it's good practice to make reusable components where possible and where it makes sense. When working with forms a very common field is the good old `Input` field. When using a react component from a component library in react-hook-form it requires the use of the Controller component from their library. It acts as a wrapper component and makes it easier for you to work with these controlled components.

Below is an example of a reusable Controlled Text Input field:

import { ReactNode } from 'react';
import { Box, Input } from '@mantine/core';
import { Control, Controller } from 'react-hook-form';

export type ControlledTextFieldProps = {
  name: string;
  control: Control<any>;
  label?: string | ReactNode;
  type: string;
  rules?: any;
  disabled?: boolean;
  helperText?: string;
  placeholder?: string;
};

const ControlledTextField = ({
  name,
  control,
  type,
  label,
  rules,
  disabled,
  helperText,
  placeholder,
}: ControlledTextFieldProps) => {

  return (
    <Box my={8} w="100%">
      <Controller
        name={name}
        control={control}
        defaultValue=""
        render={({ field, fieldState: { error } }) => (
          <Input.Wrapper error={error?.message} description={helperText} label={label || name}>
            <Input
              name={name}
              onChange={field.onChange}
              invalid={!!error}
              type={type}
              value={field.value === null ? '' : field.value}
              checked={field.value}
              disabled={disabled}
              placeholder={placeholder}
            />
          </Input.Wrapper>
        )}
        rules={rules}
      />
    </Box>
  );
};

export default ControlledTextField;

Quite a bit in going on here so let me break it down. Let's start with the Controller component from react-hook-form:

<Controller
  control={control}
  name="test"
  render={({
    field: { onChange, onBlur, value, name, ref },
    fieldState: { invalid, isTouched, isDirty, error },
    formState,
  }) => (
    // Component goes here
  )}
/>

This component needs a control prop passed down which comes from the useForm hook. This component also uses render props which is a function that returns a React element and provides the ability to attach events and value into the component. This provides different events such as onChange, onBlur etc to the child component. So when the Controlled Component (say an <Input /> field) is used, you can attach the Controllers onChange event to it. This means react-hook-form can always keep track of the Controlled Components state! Nice!

This component also uses render props which is a function that returns a React element and provides the ability to attach events and value into the component.

There is also a `rules` prop which can be passed down. This enables you to pass down validation rules to the particular field. Something like this:

rules={{ required: true }}

We can then check out the Input field from the top Code Example:

<Input
  name={name}
  onChange={field.onChange}
  invalid={!!error}
  type={type}
  value={field.value === null ? '' : field.value}
  checked={field.value}
  disabled={disabled}
  placeholder={placeholder}
/>

Here we are using the `field` object passed down from the render prop to plug in the Input component. Therefore the value or the onChange event can be connected to the react-hook-form state and it can all be managed from there. So when the form is submitted the current state of each field connected this way will be available.

Conclusion

When it comes to any website, forms can play a crucial role in gathering user data. Having a good toolkit in place for creating forms is crucial to any Frontend Developer. React-hook-form provides a great and reliable library for working with form data and to be able to use this along with a component library enables you to create good looking, well-functioning forms.

Subscribe to My Weekly Updates on Medium!

Enjoyed This Post?

If you found this blog post helpful, why not stay updated with my latest content? Subscribe to receive email notifications every time I publish.

If you're feeling really generous you can buy me a coffee. (Btw, I really like coffee…)

What You'll Get

  • Exciting Discoveries: Be the first to know about the latest tools and libraries.
  • How-To Guides: Step-by-step articles to enhance your development skills.
  • Opinion Pieces: Thought-provoking insights into the world of frontend development.

Join Our Community

I live in the vibrant city of Prague, Czech Republic, with my family. My blog is more than just articles; it's a community of like-minded developers who share a love for innovation and learning.

About me

I'm a passionate Frontend Developer specialising in React and TypeScript. My professional journey revolves around exploring and mastering new tools and libraries within the JavaScript ecosystem.

Check out my LinkedIn and Github if you are interested.

Adam Drake AI Selfie

Written by Adam Drake

Adam Drake is a Frontend React Developer who is very passionate about the quality of the web. He lives with his wife and three children in Prague in the Czech Republic.

Adam Drakes Site © 2025