diff --git a/packages/components/autocomplete/__tests__/autocomplete.test.tsx b/packages/components/autocomplete/__tests__/autocomplete.test.tsx
index b61c57ed8b..73ffcb3b5b 100644
--- a/packages/components/autocomplete/__tests__/autocomplete.test.tsx
+++ b/packages/components/autocomplete/__tests__/autocomplete.test.tsx
@@ -235,6 +235,50 @@ describe("Autocomplete", () => {
expect(autocomplete).toHaveFocus();
});
+ it("should clear value 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();
+
+ // select the target item
+ await act(async () => {
+ await userEvent.click(clearButton);
+ });
+
+ // assert that the input has empty value
+ expect(autocomplete).toHaveValue("");
+
+ // assert that input is focused
+ expect(autocomplete).toHaveFocus();
+ });
+
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 b3c9890764..f70f631881 100644
--- a/packages/components/autocomplete/src/use-autocomplete.ts
+++ b/packages/components/autocomplete/src/use-autocomplete.ts
@@ -364,7 +364,6 @@ export function useAutocomplete(originalProps: UseAutocomplete
const onClear = useCallback(() => {
state.setInputValue("");
state.setSelectedKey(null);
- state.close();
}, [state]);
const onFocus = useCallback(
diff --git a/packages/components/autocomplete/stories/autocomplete.stories.tsx b/packages/components/autocomplete/stories/autocomplete.stories.tsx
index e5758cf07e..ca4db45df2 100644
--- a/packages/components/autocomplete/stories/autocomplete.stories.tsx
+++ b/packages/components/autocomplete/stories/autocomplete.stories.tsx
@@ -3,6 +3,7 @@ import type {ValidationResult} from "@react-types/shared";
import React, {Key} from "react";
import {Meta} from "@storybook/react";
import {useForm} from "react-hook-form";
+import {useFilter} from "@react-aria/i18n";
import {autocomplete, input, button} from "@nextui-org/theme";
import {
Pokemon,
@@ -161,6 +162,76 @@ const FormTemplate = ({color, variant, ...args}: AutocompleteProps) => {
);
};
+const FullyControlledTemplate = () => {
+ // Store Autocomplete input value, selected option, open state, and items
+ // in a state tracker
+ const [fieldState, setFieldState] = React.useState({
+ selectedKey: "",
+ inputValue: "",
+ items: animalsData,
+ });
+
+ // Implement custom filtering logic and control what items are
+ // available to the Autocomplete.
+ const {startsWith} = useFilter({sensitivity: "base"});
+
+ // Specify how each of the Autocomplete values should change when an
+ // option is selected from the list box
+ const onSelectionChange = (key) => {
+ // eslint-disable-next-line no-console
+ console.log(`onSelectionChange ${key}`);
+ setFieldState((prevState) => {
+ let selectedItem = prevState.items.find((option) => option.value === key);
+
+ return {
+ inputValue: selectedItem?.label || "",
+ selectedKey: key,
+ items: animalsData.filter((item) => startsWith(item.label, selectedItem?.label || "")),
+ };
+ });
+ };
+
+ // Specify how each of the Autocomplete values should change when the input
+ // field is altered by the user
+ const onInputChange = (value) => {
+ // eslint-disable-next-line no-console
+ console.log(`onInputChange ${value}`);
+ setFieldState((prevState: any) => ({
+ inputValue: value,
+ selectedKey: value === "" ? null : prevState.selectedKey,
+ items: animalsData.filter((item) => startsWith(item.label, value)),
+ }));
+ };
+
+ // Show entire list if user opens the menu manually
+ const onOpenChange = (isOpen, menuTrigger) => {
+ if (menuTrigger === "manual" && isOpen) {
+ setFieldState((prevState) => ({
+ inputValue: prevState.inputValue,
+ selectedKey: prevState.selectedKey,
+ items: animalsData,
+ }));
+ }
+ };
+
+ return (
+
+ {(item) => {item.label}}
+
+ );
+};
+
const MirrorTemplate = ({color, variant, ...args}: AutocompleteProps) => (