5

I have this piece of code where I am trying to wire up the Combobox Component from Headless UI with react-hook-form. Whenever I try to enter a different value and select a different option it gives me an error saying - Cannot read properties of undefined (reading 'name')

I have tried a lot of different variations but I fail to use the Combobox with register. Any help would be appreciated. I want to use register to make this work and don't want to use the other Controller method of doing ways from react-hook-form.

import React from "react";

import { useState } from "react";
import { Combobox } from "@headlessui/react";
import { useForm } from "react-hook-form";

const people = [
  { id: 1, name: "Durward Reynolds" },
  { id: 2, name: "Kenton Towne" },
  { id: 3, name: "Therese Wunsch" },
  { id: 4, name: "Benedict Kessler" },
  { id: 5, name: "Katelyn Rohan" },
];

function Example() {
  const [query, setQuery] = useState("");

  const filteredPeople =
    query === ""
      ? people
      : people.filter((person) => {
          return person.name.toLowerCase().includes(query.toLowerCase());
        });

  const {
    register,
    handleSubmit,
    setValue,
    formState: { errors },
  } = useForm();

  const submit = (data) => {
    console.log(JSON.stringify(data));
  };

  return (
    <form onSubmit={handleSubmit(submit)}>
      <Combobox
        as="div"
        name="assignee"
        defaultValue={people[0]}
        {...register("assignee")}
      >
        <Combobox.Input
          onChange={(event) => setQuery(event.target.value)}
          displayValue={(person) => person.name}
        />
        <Combobox.Options>
          {filteredPeople.map((person) => (
            <Combobox.Option key={person.id} value={person}>
              {person.name}
            </Combobox.Option>
          ))}
        </Combobox.Options>
      </Combobox>
      <button>Submit</button>
    </form>
  );
}

export default function check() {
  return (
    <div>
      <Example />
    </div>
  );
}
Sunny
  • 708
  • 1
  • 4
  • 21
Nilan Saha
  • 191
  • 1
  • 9

2 Answers2

0

It's likely not a good idea to attach react-hook-form handlers to the Combobox directly.

  1. Input > onChange will give you an event with a string target.value, not a Location / User / ... model from the API. Will you do a copy request to "unpack" it in handleSubmit? And, if so, – how are you going to handle an API error there?!
  1. The input might be associated with an API error at the Combobox level. You'll have to be extra careful to distinguish "successful" and "failed" strings at the form component level.

  2. The string might be non-parsable at the form component level. Especially with "multiple" mode, where you can render an aggregate info, like "3 items are selected" in the input. And THAT will be your value if you expand register to the Combobox.Input.

  3. Finally, in some other (non HeadlessUI) Combobox implementations, the value will preserve raw user input.

For example:

  1. user inputs: "United"
  2. select suggests: "United States", "United Kingdom", ...
  3. user selects some option
  4. Combobox takes a new value but the Combobox.Input value still holds "United"

You probably want to stick to a portable and future-proof approach.


The conclusion is the same: let Combobox parse and translate values for you. Provide onChange to Combobox, not Combobox.Input. But that is possible only with controlled RHF API variant.

Ivan Kleshnin
  • 1,667
  • 2
  • 21
  • 24
-2
const { register } = useFormContext();

<Combobox.Input
    {...register(id)}
    id={id}
    onChange={(event) => setQuery(event.target.value)}
/>
Mehdi Dehghani
  • 10,970
  • 6
  • 59
  • 64