diff --git a/.changeset/serious-shrimps-pump.md b/.changeset/serious-shrimps-pump.md new file mode 100644 index 000000000..d21c9e897 --- /dev/null +++ b/.changeset/serious-shrimps-pump.md @@ -0,0 +1,5 @@ +--- +"bits-ui": patch +--- + +Listbox/Combobox: gracefully handle deselect when `type="single"` diff --git a/packages/bits-ui/src/lib/bits/listbox/components/listbox.svelte b/packages/bits-ui/src/lib/bits/listbox/components/listbox.svelte index 19cf340bc..4968315b1 100644 --- a/packages/bits-ui/src/lib/bits/listbox/components/listbox.svelte +++ b/packages/bits-ui/src/lib/bits/listbox/components/listbox.svelte @@ -31,8 +31,6 @@ } } - value === undefined && (value = type === "single" ? "" : []); - useListboxRoot({ type, value: box.with( diff --git a/packages/bits-ui/src/lib/bits/listbox/listbox.svelte.ts b/packages/bits-ui/src/lib/bits/listbox/listbox.svelte.ts index c794afb27..3c28d6336 100644 --- a/packages/bits-ui/src/lib/bits/listbox/listbox.svelte.ts +++ b/packages/bits-ui/src/lib/bits/listbox/listbox.svelte.ts @@ -800,8 +800,10 @@ class ListboxItemState { // prevent any default behavior e.preventDefault(); if (this.disabled.current) return; + const isCurrentSelectedValue = this.value.current === this.root.value.current; this.root.toggleItem(this.value.current, this.label.current); - if (!this.root.isMulti) { + + if (!this.root.isMulti && !isCurrentSelectedValue) { this.root.closeMenu(); } }; diff --git a/packages/bits-ui/src/tests/listbox/listbox.test.ts b/packages/bits-ui/src/tests/listbox/listbox.test.ts index 355e80881..97e7254fb 100644 --- a/packages/bits-ui/src/tests/listbox/listbox.test.ts +++ b/packages/bits-ui/src/tests/listbox/listbox.test.ts @@ -416,6 +416,19 @@ describe("listbox - single", () => { const content = getByTestId("content"); expect(content).toBeVisible(); }); + + it("should deselect the selected item when the user clicks on the selected item", async () => { + const { getByTestId, user, trigger } = await openSingle(); + const [item0] = getItems(getByTestId); + await user.click(item0!); + expectSelected(item0!); + await user.click(trigger); + + const [item0v2] = getItems(getByTestId); + + await user.click(item0v2!); + expectNotSelected(item0v2!); + }); }); ////////////////////////////////////