radix-ui / primitives

Radix Primitives is an open-source UI component library for building high-quality, accessible design systems and web apps. Maintained by @workos.
https://radix-ui.com/primitives
MIT License
15.4k stars 770 forks source link

Possible bug using radix-select with react-hook-form #3068

Open Canfus opened 1 month ago

Canfus commented 1 month ago

Bug report

Current Behavior

While using radix-select component with react-hook-form library and pick a some value, your picked value will overrided by empty string

If we log new value ./components/select-field/select-field.tsx:37

image

We can see logs look like this

image

Reproducible example

Link to reproduce

Your environment

Software Name(s) Version
Radix Package(s) @radix-ui/react-select ^2.1.1
React n/a ^18.3.1
Browser Google Chrome dev 129.0.6628.3
Assistive tech
Node n/a 20.14.0
npm/yarn pnpm 9.3.0
Operating System Windows 10 19045.4529
fxckdead commented 2 weeks ago

I faced a similar issue today on my custom Select component, it's not really a bug.

the onChange is expecting an event React.ChangeEvent<HTMLSelectElement> (or any event from an input) so the value you must pass down needs to have at least name, value and type.

I use something like this:

function createFakeEvent<T>({
  name,
  value,
  type,
}: {
  name: string;
  value: string;
  type: "change" | "blur";
}) {
  // Create a synthetic change event
  const fakeEvent = new Event(type, {
    bubbles: true,
    cancelable: true,
  }) as unknown as React.ChangeEvent<T>;

  // Manually set the target with the desired value
  const eventTarget = { value, name } as T;

  Object.defineProperty(fakeEvent, "target", {
    writable: true,
    value: eventTarget,
  });
  Object.defineProperty(fakeEvent, "currentTarget", {
    writable: true,
    value: eventTarget,
  });

  return fakeEvent;
}

So later when I need to call it:

    const onChangeHandler = React.useCallback(
      (value: string) => {
        // default radix change handler
        onValueChange?.(value);

        const targetName = rootProps.name || "";

        onChange?.(
          createFakeEvent<HTMLSelectElement>({
            name: targetName,
            value,
            type: "change",
          }),
        );
      },
      [onChange, onValueChange, rootProps.name],
    );