diff --git a/.changeset/dirty-moles-refuse.md b/.changeset/dirty-moles-refuse.md
new file mode 100644
index 0000000000..5a73d0c78f
--- /dev/null
+++ b/.changeset/dirty-moles-refuse.md
@@ -0,0 +1,5 @@
+---
+"@nextui-org/autocomplete": patch
+---
+
+Clicking the clear button clears the selected value without closing the dropdown. (#3788)
\ No newline at end of file
diff --git a/packages/components/autocomplete/__tests__/autocomplete.test.tsx b/packages/components/autocomplete/__tests__/autocomplete.test.tsx
index ab4f6d381f..fb6162007c 100644
--- a/packages/components/autocomplete/__tests__/autocomplete.test.tsx
+++ b/packages/components/autocomplete/__tests__/autocomplete.test.tsx
@@ -223,7 +223,7 @@ describe("Autocomplete", () => {
expect(clearButton).not.toBeNull();
- // select the target item
+ // click the clear button
await act(async () => {
await userEvent.click(clearButton);
});
@@ -235,6 +235,55 @@ describe("Autocomplete", () => {
expect(autocomplete).toHaveFocus();
});
+ it("should keep the ListBox open after clicking clear button", async () => {
+ const wrapper = render(
+
+
+ Penguin
+
+
+ Zebra
+
+
+ Shark
+
+ ,
+ );
+
+ const autocomplete = wrapper.getByTestId("autocomplete");
+
+ // open the select listbox
+ await act(async () => {
+ await userEvent.click(autocomplete);
+ });
+
+ // assert that the autocomplete listbox is open
+ expect(autocomplete).toHaveAttribute("aria-expanded", "true");
+
+ let options = wrapper.getAllByRole("option");
+
+ // select the target item
+ await act(async () => {
+ await userEvent.click(options[0]);
+ });
+
+ const {container} = wrapper;
+
+ const clearButton = container.querySelector(
+ "[data-slot='inner-wrapper'] button:nth-of-type(1)",
+ )!;
+
+ expect(clearButton).not.toBeNull();
+
+ // click the clear button
+ await act(async () => {
+ await userEvent.click(clearButton);
+ });
+
+ // assert that the autocomplete listbox is open
+ expect(autocomplete).toHaveAttribute("aria-expanded", "true");
+ });
+
it("should clear value after clicking clear button (controlled)", async () => {
const wrapper = render(
@@ -267,7 +316,7 @@ describe("Autocomplete", () => {
expect(clearButton).not.toBeNull();
- // select the target item
+ /// click the clear button
await act(async () => {
await userEvent.click(clearButton);
});
@@ -279,6 +328,47 @@ describe("Autocomplete", () => {
expect(autocomplete).toHaveFocus();
});
+ it("should keep the ListBox open after clicking clear button (controlled)", async () => {
+ const wrapper = render(
+
+ {(item) => {item.value}}
+ ,
+ );
+
+ const autocomplete = wrapper.getByTestId("autocomplete");
+
+ // open the select listbox
+ await act(async () => {
+ await userEvent.click(autocomplete);
+ });
+
+ // assert that the autocomplete listbox is open
+ expect(autocomplete).toHaveAttribute("aria-expanded", "true");
+
+ let options = wrapper.getAllByRole("option");
+
+ // select the target item
+ await act(async () => {
+ await userEvent.click(options[0]);
+ });
+
+ const {container} = wrapper;
+
+ const clearButton = container.querySelector(
+ "[data-slot='inner-wrapper'] button:nth-of-type(1)",
+ )!;
+
+ expect(clearButton).not.toBeNull();
+
+ // click the clear button
+ await act(async () => {
+ await userEvent.click(clearButton);
+ });
+
+ // assert that the autocomplete listbox is open
+ expect(autocomplete).toHaveAttribute("aria-expanded", "true");
+ });
+
it("should open and close listbox by clicking selector button", async () => {
const wrapper = render(
diff --git a/packages/components/autocomplete/src/use-autocomplete.ts b/packages/components/autocomplete/src/use-autocomplete.ts
index d1cae053f3..b6a9cae1ab 100644
--- a/packages/components/autocomplete/src/use-autocomplete.ts
+++ b/packages/components/autocomplete/src/use-autocomplete.ts
@@ -385,16 +385,15 @@ export function useAutocomplete(originalProps: UseAutocomplete
},
onPress: (e: PressEvent) => {
slotsProps.clearButtonProps?.onPress?.(e);
-
if (state.selectedItem) {
state.setInputValue("");
state.setSelectedKey(null);
} else {
if (allowsCustomValue) {
state.setInputValue("");
- state.close();
}
}
+ state.open();
},
"data-visible": !!state.selectedItem || state.inputValue?.length > 0,
className: slots.clearButton({