How to implement react hook form with headlessui

Rishav Raj's avatar

Rishav Raj

React Hook Form with Headless UI: A Comprehensive Guide

Creating efficient and user-friendly forms in React applications is essential for collecting user data, handling user inputs, and building interactive web applications. This guide explores how to leverage React Hook Form alongside Headless UI to create highly customizable and accessible forms with minimal effort. By combining these tools, developers can achieve improved form performance, easier validation, and better user experiences without sacrificing flexibility.

What is React Hook Form?

React Hook Form is a lightweight library for managing forms in React applications. It embraces uncontrolled components and hooks to minimize re-renders and improve performance. React Hook Form simplifies form handling, including input validation, form submission, and error management, by leveraging the power of React hooks.

What is Headless UI?

Headless UI is a set of completely unstyled, fully accessible UI components, designed to integrate seamlessly with Tailwind CSS. It provides the functionality of common UI components without imposing any design, allowing developers to build beautiful UIs with complete control over the styling.

Integrating React Hook Form with Headless UI

This integration offers the best of both worlds: the performance and simplicity of React Hook Form with the accessibility and flexibility of Headless UI. Follow this step-by-step guide to create a form using these tools.

Prerequisites

To follow along with this blog, you should have a basic understanding of React and be familiar with React Hook Form and Headless UI. If you are new to these libraries, you can check out their respective documentation:

  • React-hook-form
  • Headlessui
  • Next-js
  • Tailwindcss

Integrating Switch with React Hook Form

To integrate Headless UI components like Switch with React Hook Form, you'll need to utilize the Controller component and the control prop provided by React Hook Form

Integration

Setting Up Your Project

First, ensure you have a React project set up. If you need to create a new project, you can do so using Create React App:

npx create-react-app my-app
cd my-app
npm start

Next, install React Hook Form and Headless UI:

npm install react-hook-form @headlessui/react

Approach #1: By using "control" prop with useController()

We need to get control object from useForm() when creating a form and pass it to the custom component.

This object contains methods for registering components into React Hook Form.

// App.js
import { Switch } from '@headlessui/react';
import { useForm } from 'react-hook-form';
import CustomSwitch from './CustomSwitch';
 
export default function App() {
  const { handleSubmit, control } = useForm();
  const onSubmit = async (formData) => {
    console.log(formData);
  };
  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <Switch.Group as="div">
        {/* 👇 We're setting name and passing control object from useForm() */}
        <CustomSwitch name="default_header" control={control} />
      </Switch.Group>
 
      <button type="submit">Submit</button>
    </form>
  );
}
// CustomSwitch.js
import { useController } from 'react-hook-form';
 
import { Switch } from '@headlessui/react';
import { useForm } from 'react-hook-form';
import CustomSwitch from './CustomSwitch';
 
export const CustomSwitch = (props) => {
  const {
    field: { value, onChange },
  } = useController(props);
 
  return (
    <>
      <Switch checked={Boolean(value)} onChange={onChange} />
    </>
  );
};
 
export default CustomSwitch;

And in the custom component we can pass the props to useController() hooks to get the value of the field and also other callback functions like onChange

Approach #2: Render props approach

// App.js
import { Switch } from '@headlessui/react';
import { useForm, Controller } from 'react-hook-form';
import CustomSwitch from './CustomSwitch';
 
export default function App() {
  const { handleSubmit, control } = useForm();
  const onSubmit = async (formData) => {
    console.log(formData);
  };
  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <Controller
        render={({ field }) => <input type="text" {...props} />}
        name="name"
        control={control}
      />
 
      <button type="submit">Submit</button>
    </form>
  );
}

Conclusion

In this example, you've seen how to combine React Hook Form with Headless UI to create an accessible, customizable, and validation-ready form. This setup leverages the strengths of both libraries, offering an efficient way to handle form state and UI components in React applications. Remember, the true power of these libraries is unlocked when you tailor them to fit the unique needs of your project, experimenting with their various features and options.

Links and references