From 0c6494e9390df4a162b8c44df4674a98f04898db Mon Sep 17 00:00:00 2001 From: Serghei Gurgurov Date: Fri, 18 Apr 2025 20:30:54 +0200 Subject: [PATCH 1/2] fix(material/select): select shrinking after scroll Fixes a bug in the select component that makes it shrink on scroll and not grow back when it get's back into view Fixes #30901 --- src/material/select/select.html | 1 + 1 file changed, 1 insertion(+) diff --git a/src/material/select/select.html b/src/material/select/select.html index 6eaecee7f5c3..9b02ddfd892e 100644 --- a/src/material/select/select.html +++ b/src/material/select/select.html @@ -40,6 +40,7 @@ [cdkConnectedOverlayPositions]="_positions" [cdkConnectedOverlayWidth]="_overlayWidth" [cdkConnectedOverlayFlexibleDimensions]="true" + [cdkConnectedOverlayGrowAfterOpen]="true" (detach)="close()" (backdropClick)="close()" (overlayKeydown)="_handleOverlayKeydown($event)"> From 13f339482bc1d0723cf5b716a05e1985f04b4da9 Mon Sep 17 00:00:00 2001 From: Serghei Gurgurov Date: Sat, 19 Apr 2025 01:35:27 +0200 Subject: [PATCH 2/2] fix(cdk/listbox): avoid resetting scroll position when using mouse The CDK listbox has some logic that forwards focus to the first item when the host is focused. The problem is that every time the user clicks on the scrollbar, they blur the current item and focus the listbox which then forwards focus back to the first item which in turn causes the scroll position to jump to the top. These changes add some logic to not forward focus when focus comes from a mouse interaction. Fixes #30900 --- src/cdk/listbox/listbox.ts | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/src/cdk/listbox/listbox.ts b/src/cdk/listbox/listbox.ts index b4405757ea89..d25fe9daa6ac 100644 --- a/src/cdk/listbox/listbox.ts +++ b/src/cdk/listbox/listbox.ts @@ -9,6 +9,7 @@ import { _IdGenerator, ActiveDescendantKeyManager, + FocusMonitor, Highlightable, ListKeyManagerOption, } from '../a11y'; @@ -243,7 +244,6 @@ export class CdkOption implements ListKeyManagerOption, Highlightab '[attr.aria-multiselectable]': 'multiple', '[attr.aria-activedescendant]': '_getAriaActiveDescendant()', '[attr.aria-orientation]': 'orientation', - '(focus)': '_handleFocus()', '(keydown)': '_handleKeydown($event)', '(focusout)': '_handleFocusOut($event)', '(focusin)': '_handleFocusIn()', @@ -269,6 +269,7 @@ export class CdkListbox implements AfterContentInit, OnDestroy, Con } private _id: string; private _generatedId = inject(_IdGenerator).getId('cdk-listbox-'); + private _focusMonitor = inject(FocusMonitor); /** The tabindex to use when the listbox is enabled. */ @Input('tabindex') @@ -462,6 +463,7 @@ export class CdkListbox implements AfterContentInit, OnDestroy, Con } this._initKeyManager(); + this._handleFocus(); // Update the internal value whenever the options or the model value changes. merge(this.selectionModel.changed, this.options.changes) @@ -477,6 +479,7 @@ export class CdkListbox implements AfterContentInit, OnDestroy, Con } ngOnDestroy() { + this._focusMonitor.stopMonitoring(this.element); this._cleanupWindowBlur?.(); this.listKeyManager?.destroy(); this.destroyed.next(); @@ -698,15 +701,26 @@ export class CdkListbox implements AfterContentInit, OnDestroy, Con /** Called when the listbox receives focus. */ protected _handleFocus() { - if (!this.useActiveDescendant) { - if (this.selectionModel.selected.length > 0) { - this._setNextFocusToSelectedOption(); - } else { - this.listKeyManager.setNextItemActive(); - } + this._focusMonitor + .monitor(this.element, false) + .pipe(takeUntil(this.destroyed)) + .subscribe(focusOrigin => { + // Don't forward focus on mouse interactions, because it can + // mess with the user's scroll position. See #30900. + if (focusOrigin === 'mouse' || focusOrigin === null) { + return; + } - this._focusActiveOption(); - } + if (!this.useActiveDescendant) { + if (this.selectionModel.selected.length > 0) { + this._setNextFocusToSelectedOption(); + } else { + this.listKeyManager.setNextItemActive(); + } + + this._focusActiveOption(); + } + }); } /** Called when the user presses keydown on the listbox. */