headlessui icon indicating copy to clipboard operation
headlessui copied to clipboard

Combobox firing select value onChange when clearing the input value

Open david10sing opened this issue 1 year ago • 2 comments

https://github.com/tailwindlabs/headlessui/blob/5eb3b12a95a980397d4cf055f120691911631e85/packages/%40headlessui-react/src/components/combobox/combobox.tsx#L1309

Based on the line above and the preceding comment, it looks like when the user clears the input value, there is an onChange event fired.

Is there a reason for this? I would have thought that the input value and the selected option concerns should be different.

Why would we want to trigger an onChange and send null when the user is just typing and clearing the input field?

david10sing avatar Oct 17 '24 20:10 david10sing

This is a reproduction: https://stackblitz.com/edit/vitejs-vite-6e5rus1w?file=src%2FApp.tsx,src%2Findex.css,src%2Fmain.tsx&terminal=dev

Is this a new change in v2 or it's always like that? (Yes it is)

@RobinMalfait Sorry for the ping. The intention is reasonable here, but at least it should provide an option or be explicitly documented in the docs. Otherwise, it's like surprising behaviour, where no one knows.

Explicitly passing null to onChange without documenting it anywhere should be breaking most of the usage.

image This should at least be T | null in the docs from my perspective.

Thanks.

xsjcTony avatar Jan 09 '25 23:01 xsjcTony

Does this functionality makes sense? When we clear the search input, the value probably shouldn’t be set to null, right?

Since we’re always working with a string when we modify this value, it should just be an empty string instead here, correct?

kwconrad avatar Feb 11 '25 15:02 kwconrad

Hey!

In @headlessui/react v1 the Combobox could be marked as nullable which allows you to clear the value which in turn uses null as the onChange value when you cleared the input. We noticed that we essentially always wanted the component to be nullable, so in v2 we made the combobox nullable by default.

We did document this in the release notes when we published v2: https://github.com/tailwindlabs/headlessui/releases/tag/%40headlessui%2Freact%40v2.0.0#:~:text=Comboboxes%20now%20always%20support%20empty%20values

If you don't want to the value to be nullable, then you can use something like this:

 <Combobox
   value={selected}
-  onChange={setSelected}
+  onChange={(newValue) => setSelected((oldValue) => newValue ?? oldValue)}
   onClose={() => setQuery('')}
 >

or you could also ignore the newValue if it is null, that's up to you.


@xsjcTony Good catch! I've updated the docs to include the | null for the onChange callback.


@kwconrad The ComboboxInput deals with strings, but the actual Combobox can deal with any kind of value. If we were only dealing with strings then we could call the onChange with '' but that value doesn't make sense for objects or anything else, which is why we picked null instead.

Note: If you are dealing with any other type than a string, then that's why you would need the displayValue https://headlessui.com/react/combobox#binding-objects-as-values

Going to close this since this is the expected behavior, but I did update the docs to include the T | null change.

RobinMalfait avatar Sep 19 '25 16:09 RobinMalfait