Provide a general summary of the issue here
Package
react-aria-components / @react-stately/combobox
Summary
When selectionMode="multiple" and allowsCustomValue={true} are used together on a ComboBox, three keyboard interactions — Escape, Tab, and blur with non-empty input — silently wipe the entire current selection. This makes the combination effectively unusable for multi-select comboboxes that allow custom values.
Root Cause (located in source)
In useComboBoxState, the selectedKey variable is hardcoded to null for multiple selection mode:
// useComboBoxState.js
let selectedKey = selectionMode === 'single' ? selectionManager.firstSelectedKey : null;
This means itemText is always "" in multiple mode:
const itemText = selectedKey != null ? collection.getItem(selectedKey)?.textValue ?? '' : '';
So commitValue() always routes to commitCustomValue() whenever inputValue is non-empty:
const commitValue = () => {
if (allowsCustomValue) {
inputValue === itemText ? commitSelection() : commitCustomValue(); // itemText is always "" in multiple
}
};
And commitCustomValue() unconditionally clears all selections in multiple mode:
let commitCustomValue = () => {
let value = selectionMode === 'multiple' ? EMPTY_VALUE : null; // EMPTY_VALUE = []
setValue(value);
closeMenu();
};
Additionally, revert() — called directly on Escape — also routes to commitCustomValue() whenever allowsCustomValue && selectedKey == null, which is always true in multiple mode:
let revert = () => {
if (allowsCustomValue && selectedKey == null) commitCustomValue(); // always true for multiple
else commitSelection();
};
🤔 Expected Behavior?
Scenarios and Expected vs Actual Behavior
Bug 1 — Tab out clears entire selection (most critical)
Steps:
Select "India" and "Japan" from the list
Click the input, type any text (e.g. "Ca")
Press Tab to move focus to the next element
Expected: Tab commits or discards the typed text; previously selected items ("India", "Japan") remain selected.
Bug 2 — Escape clears entire selection
Steps:
Use keyboard (ArrowDown + Enter) to select "India" from the list
The popover remains open (expected in multiple mode)
Press Escape to dismiss the popover
Expected: Popover closes, "India" remains selected.
Bug 3 — Blur with non-empty input clears entire selection
Steps:
Select "India" from the list
Type "Ca" in the input (do not select anything)
Click outside the ComboBox
Expected: "Ca" is discarded (not a known item), "India" remains selected.
Bug 4 — Enter on a list item (without keyboard navigation) does not select it
Steps:
Type "India" (matching a list item); popover opens
Do not press ArrowDown; press Enter directly
Expected: "India" is selected (the text unambiguously matches one item).
😯 Current Behavior
Scenarios and Expected vs Actual Behavior
Bug 1 — Tab out clears entire selection (most critical)
Steps:
Select "India" and "Japan" from the list
Click the input, type any text (e.g. "Ca")
Press Tab to move focus to the next element
Actual: commit() → commitValue() → commitCustomValue() → setValue([]). Entire selection is wiped.
Bug 2 — Escape clears entire selection
Steps:
Use keyboard (ArrowDown + Enter) to select "India" from the list
The popover remains open (expected in multiple mode)
Press Escape to dismiss the popover
Actual: revert() → commitCustomValue() → setValue([]). "India" is removed.
Bug 3 — Blur with non-empty input clears entire selection
Steps:
Select "India" from the list
Type "Ca" in the input (do not select anything)
Click outside the ComboBox
Actual: blur → commitValue() → commitCustomValue() → setValue([]). "India" is removed.
Bug 4 — Enter on a list item (without keyboard navigation) does not select it
Steps:
Type "India" (matching a list item); popover opens
Do not press ArrowDown; press Enter directly
Actual: commit() → focusedKey == null → commitValue() → commitCustomValue() → setValue([]). Nothing is selected.
💁 Possible Solution
### Expected Fix
commitCustomValue() and revert() should not clear selectedKeys when selectionMode="multiple". The intent of commitCustomValue for multiple selection should be:
- Clear
inputValue and close the menu
- Preserve the existing
selectedKeys
For commitValue(), when selectionMode="multiple", itemText should not be derived from a single selectedKey. Either compare against an empty string only when inputValue is truly empty, or treat any typed text as a potential custom entry to add (not a reason to clear).
🔦 Context
No response
🖥️ Steps to Reproduce
Reproduction Steps
function Demo() {
const [selectedKeys, setSelectedKeys] = useState([]);
const [inputValue, setInputValue] = useState('');
const items = [
{ id: 1, name: 'India' },
{ id: 2, name: 'Japan' },
{ id: 3, name: 'Canada' },
];
return (
<ComboBox
selectionMode="multiple"
allowsCustomValue
defaultItems={items}
selectedKey={selectedKeys}
onChange={setSelectedKeys}
inputValue={inputValue}
onInputChange={setInputValue}
>
<Label>Countries</Label>
<Input />
<Button />
<Popover>
<ListBox>
{(item) => <ListBoxItem id={item.id}>{item.name}</ListBoxItem>}
</ListBox>
</Popover>
</ComboBox>
);
}
Version
react-aria-components@1.17.0
What browsers are you seeing the problem on?
Chrome
If other, please specify.
react-aria-components@1.17.0
What operating system are you using?
Mac OS
🧢 Your Company/Team
No response
🕷 Tracking Issue
No response
Provide a general summary of the issue here
Package
react-aria-components / @react-stately/combobox
Summary
When selectionMode="multiple" and allowsCustomValue={true} are used together on a ComboBox, three keyboard interactions — Escape, Tab, and blur with non-empty input — silently wipe the entire current selection. This makes the combination effectively unusable for multi-select comboboxes that allow custom values.
Root Cause (located in source)
In
useComboBoxState, theselectedKeyvariable is hardcoded tonullfor multiple selection mode:// useComboBoxState.js
let selectedKey = selectionMode === 'single' ? selectionManager.firstSelectedKey : null;This means
itemTextis always""in multiple mode:const itemText = selectedKey != null ? collection.getItem(selectedKey)?.textValue ?? '' : '';So
commitValue()always routes tocommitCustomValue()wheneverinputValueis non-empty:And
commitCustomValue()unconditionally clears all selections in multiple mode:Additionally,
revert()— called directly onEscape— also routes tocommitCustomValue()wheneverallowsCustomValue && selectedKey == null, which is alwaystruein multiple mode:🤔 Expected Behavior?
Scenarios and Expected vs Actual Behavior
Bug 1 — Tab out clears entire selection (most critical)
Steps:
Select "India" and "Japan" from the list
Click the input, type any text (e.g. "Ca")
Press Tab to move focus to the next element
Expected: Tab commits or discards the typed text; previously selected items ("India", "Japan") remain selected.
Bug 2 — Escape clears entire selection
Steps:
Use keyboard (ArrowDown + Enter) to select "India" from the list
The popover remains open (expected in multiple mode)
Press Escape to dismiss the popover
Expected: Popover closes, "India" remains selected.
Bug 3 — Blur with non-empty input clears entire selection
Steps:
Select "India" from the list
Type "Ca" in the input (do not select anything)
Click outside the ComboBox
Expected: "Ca" is discarded (not a known item), "India" remains selected.
Bug 4 — Enter on a list item (without keyboard navigation) does not select it
Steps:
Type "India" (matching a list item); popover opens
Do not press ArrowDown; press Enter directly
Expected: "India" is selected (the text unambiguously matches one item).
😯 Current Behavior
Scenarios and Expected vs Actual Behavior
Bug 1 — Tab out clears entire selection (most critical)
Steps:
Select "India" and "Japan" from the list
Click the input, type any text (e.g. "Ca")
Press Tab to move focus to the next element
Actual:
commit() → commitValue() → commitCustomValue() → setValue([]).Entire selection is wiped.Bug 2 — Escape clears entire selection
Steps:
Use keyboard (ArrowDown + Enter) to select "India" from the list
The popover remains open (expected in multiple mode)
Press Escape to dismiss the popover
Actual:
revert() → commitCustomValue() → setValue([]). "India" is removed.Bug 3 — Blur with non-empty input clears entire selection
Steps:
Select "India" from the list
Type "Ca" in the input (do not select anything)
Click outside the ComboBox
Actual:
blur → commitValue() → commitCustomValue() → setValue([]). "India" is removed.Bug 4 — Enter on a list item (without keyboard navigation) does not select it
Steps:
Type "India" (matching a list item); popover opens
Do not press ArrowDown; press Enter directly
Actual:
commit() → focusedKey == null → commitValue() → commitCustomValue() → setValue([]). Nothing is selected.💁 Possible Solution
### Expected Fix
commitCustomValue()andrevert()should not clearselectedKeyswhenselectionMode="multiple". The intent ofcommitCustomValuefor multiple selection should be:inputValueand close the menuselectedKeysFor
commitValue(), whenselectionMode="multiple",itemTextshould not be derived from a singleselectedKey. Either compare against an empty string only wheninputValueis truly empty, or treat any typed text as a potential custom entry to add (not a reason to clear).🔦 Context
No response
🖥️ Steps to Reproduce
Reproduction Steps
Version
react-aria-components@1.17.0
What browsers are you seeing the problem on?
Chrome
If other, please specify.
react-aria-components@1.17.0
What operating system are you using?
Mac OS
🧢 Your Company/Team
No response
🕷 Tracking Issue
No response