Hello I'm using the Combobox from React aria I have followed official docs however once I enter something in the input there is no filtering happening. For instance if you write PHP in the combobox it still shows the rest of entries which is incorrect behavior.
I won't post the code for styling and types because it doesn't influence the behavior.
In a Listbox I have noticed that state.collection.keyMap
is not being update, but that just my guess.
Here is my code
//Autocomplete wrapper
export const Autocomplete = ({
options,
isLoading,
isDisabled
}: AutocompleteProps) => {
return (
<div>
<ComboBox items={options} isDisabled={isDisabled}>
{(item) => (
<Item textValue={item.label} key={item.label}>
<p>{item.label}</p>
</Item>
)}
</ComboBox>
</div>
);
};
// Combobox with hook to enclose all state
import { useComboBox } from "./useCombobox";
export { Item, Section } from "react-stately";
export function ComboBox<T extends object>(props: ComboBoxProps<T>) {
const {
buttonProps,
inputProps,
listBoxProps,
buttonRef,
inputRef,
listBoxRef,
popoverRef,
state
} = useComboBox(props);
return (
<Styled.Wrapper>
<Styled.InputGroup isFocused={state.isFocused}>
<Styled.Input
{...inputProps}
ref={inputRef}
isFocused={state.isFocused}
aria-label="label"
placeholder="placeholder"
/>
<Styled.Button {...buttonProps} ref={buttonRef}>
<span aria-hidden="true">▼</span>
</Styled.Button>
</Styled.InputGroup>
{state.isOpen && (
<Popover
popoverRef={popoverRef}
triggerRef={inputRef}
state={state}
isNonModal
placement="bottom start"
>
<ListBox {...listBoxProps} listBoxRef={listBoxRef} state={state} />
</Popover>
)}
</Styled.Wrapper>
);
}
// facade hook for managing the state
import * as React from "react";
import {
useButton,
useFilter,
useComboBox as useAriaComboBox
} from "react-aria";
import { useComboBoxState } from "react-stately";
import type { ComboBoxProps } from "@react-types/combobox";
export const useComboBox = <T extends object>(props: ComboBoxProps<T>) => {
const { contains } = useFilter({ sensitivity: "base" });
const state = useComboBoxState({ ...props, defaultFilter: contains });
const buttonRef = React.useRef(null);
const inputRef = React.useRef(null);
const listBoxRef = React.useRef(null);
const popoverRef = React.useRef(null);
const {
buttonProps: triggerProps,
inputProps,
listBoxProps
} = useAriaComboBox(
{
...props,
inputRef,
buttonRef,
listBoxRef,
popoverRef
},
state
);
const { buttonProps } = useButton(triggerProps, buttonRef);
return {
buttonProps,
inputProps,
listBoxProps,
buttonRef,
inputRef,
listBoxRef,
popoverRef,
state
};
};
//Listbox and options
const OptionContext = React.createContext<OptionContextValue>({
labelProps: {},
descriptionProps: {}
});
export const Option = ({ item, state }: OptionProps) => {
const ref = React.useRef<HTMLLIElement>(null);
const { optionProps, labelProps, descriptionProps, isSelected } = useOption(
{
key: item.key
},
state,
ref
);
return (
<Styled.ListItem {...optionProps} $isSelected={isSelected} ref={ref}>
<Styled.ItemContent>
<OptionContext.Provider value={{ labelProps, descriptionProps }}>
{item.rendered}
</OptionContext.Provider>
</Styled.ItemContent>
{isSelected && <span role="img">✅</span>}
</Styled.ListItem>
);
};
export const ListBox = (props: ListBoxProps) => {
const ref = React.useRef<HTMLUListElement>(null);
const { listBoxRef = ref, state } = props;
const { listBoxProps } = useListBox(props, state, listBoxRef);
console.log("state.collection", state.collection.keyMap);
return (
<Styled.List {...listBoxProps} ref={listBoxRef}>
{[...state.collection].map((item) => (
<Option key={item.key} item={item} state={state} />
))}
</Styled.List>
);
};
Live demo: https://codesandbox.io/s/flamboyant-rosalind-py0ply?file=/src/Combobox/Listbox/Listbox.styles.ts