What is affected?
Component
Description
When an option is selected via mouse click in md-outlined-select or md-filled-select, pressing any printable key while the select is closed and focused causes the selection to change unexpectedly. This does not occur when the option is selected via keyboard (arrow keys + Enter).
The root cause is a tabindex desync between the mouse and keyboard selection paths. When the dropdown is open, the ListController manages roving tabindex — keyboard navigation calls deactivateItem (tabIndex = -1) and activateItem (tabIndex = 0). Keyboard selection goes through this path, so after closing, the correct option has tabIndex = 0.
Mouse-click selection bypasses the ListController. The click fires a close-menu event with reason.kind === 'click-selection', and handleCloseMenu calls selectItem(), which correctly updates .selected and the internal VALUE/displayText — but never updates tabIndex on the menu items. The previously selected option retains tabIndex = 0.
When a printable key is subsequently pressed, handleKeydown delegates to the TypeaheadController. In beginTypeahead(), the controller locates the "active" item by finding the item with tabIndex === 0 — which is the old selection. The typeahead then searches from that stale position and selects whichever option matches the keystroke, making the selection appear to revert.
Reproduction
code pen
Steps to reproduce:
- Render an md-outlined-select (or md-filled-select) with multiple options (e.g., "Apple", "Banana", "Orange")
- "Apple" is the initial selection
- Click the select to open the dropdown
- Click "Orange" with the mouse — the select now displays "Orange"
- Without clicking elsewhere, press the a key
Expected: The select remains on "Orange" (or performs typeahead from "Orange" as the active baseline).
Actual: The select reverts to "Apple" because the typeahead controller found "Apple" via its stale tabIndex = 0 and matched the a keystroke to it.
Note: If step 4 is done with the keyboard (arrow to "Orange", press Enter), pressing a in step 5 does not revert the selection.
Workaround
select.addEventListener('change', () => {
for (const option of select.options) {
option.tabIndex = option.selected ? 0 : -1;
}
});
Is this a regression?
No or unsure. This never worked, or I haven't tried before.
Affected versions
Fails in 2.4.1
Browser/OS/Node environment
@material/web version: 2.4.1
Browsers: Reproducible in Chrome, Edge, Firefox (all current stable)
Also reproducible on the official Material Web documentation/demo page
What is affected?
Component
Description
When an option is selected via mouse click in md-outlined-select or md-filled-select, pressing any printable key while the select is closed and focused causes the selection to change unexpectedly. This does not occur when the option is selected via keyboard (arrow keys + Enter).
The root cause is a tabindex desync between the mouse and keyboard selection paths. When the dropdown is open, the ListController manages roving tabindex — keyboard navigation calls deactivateItem (tabIndex = -1) and activateItem (tabIndex = 0). Keyboard selection goes through this path, so after closing, the correct option has tabIndex = 0.
Mouse-click selection bypasses the ListController. The click fires a close-menu event with reason.kind === 'click-selection', and handleCloseMenu calls selectItem(), which correctly updates .selected and the internal VALUE/displayText — but never updates tabIndex on the menu items. The previously selected option retains tabIndex = 0.
When a printable key is subsequently pressed, handleKeydown delegates to the TypeaheadController. In beginTypeahead(), the controller locates the "active" item by finding the item with tabIndex === 0 — which is the old selection. The typeahead then searches from that stale position and selects whichever option matches the keystroke, making the selection appear to revert.
Reproduction
code pen
Steps to reproduce:
Expected: The select remains on "Orange" (or performs typeahead from "Orange" as the active baseline).
Actual: The select reverts to "Apple" because the typeahead controller found "Apple" via its stale tabIndex = 0 and matched the a keystroke to it.
Note: If step 4 is done with the keyboard (arrow to "Orange", press Enter), pressing a in step 5 does not revert the selection.
Workaround
Is this a regression?
No or unsure. This never worked, or I haven't tried before.
Affected versions
Fails in 2.4.1
Browser/OS/Node environment
@material/web version: 2.4.1
Browsers: Reproducible in Chrome, Edge, Firefox (all current stable)
Also reproducible on the official Material Web documentation/demo page