Skip to content

Commit c4e4608

Browse files
committed
fix(material/autocomplete): incorrectly resolving focused element in shadow DOM (#30619)
There are a few places where the autocomplete was checking if it has focus which were breaking down when inside the shadow DOM, because `document.activeElement` will point to the closest shadow root. These changes consolidate the places where we check for focus and use our utility for resolving the focused element through shadow boundaries. Fixes #30611. (cherry picked from commit e61d152)
1 parent 596a85f commit c4e4608

File tree

1 file changed

+9
-7
lines changed

1 file changed

+9
-7
lines changed

src/material/autocomplete/autocomplete-trigger.ts

+9-7
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,9 @@ import {
1919
PositionStrategy,
2020
ScrollStrategy,
2121
} from '@angular/cdk/overlay';
22-
import {_getEventTarget} from '@angular/cdk/platform';
22+
import {_getEventTarget, _getFocusedElementPierceShadowDom} from '@angular/cdk/platform';
2323
import {TemplatePortal} from '@angular/cdk/portal';
2424
import {ViewportRuler} from '@angular/cdk/scrolling';
25-
import {DOCUMENT} from '@angular/common';
2625
import {
2726
AfterViewInit,
2827
ChangeDetectorRef,
@@ -147,7 +146,6 @@ export class MatAutocompleteTrigger
147146
private _changeDetectorRef = inject(ChangeDetectorRef);
148147
private _dir = inject(Directionality, {optional: true});
149148
private _formField = inject<MatFormField | null>(MAT_FORM_FIELD, {optional: true, host: true});
150-
private _document = inject(DOCUMENT);
151149
private _viewportRuler = inject(ViewportRuler);
152150
private _scrollStrategy = inject(MAT_AUTOCOMPLETE_SCROLL_STRATEGY);
153151
private _renderer = inject(Renderer2);
@@ -216,8 +214,7 @@ export class MatAutocompleteTrigger
216214
// If the user blurred the window while the autocomplete is focused, it means that it'll be
217215
// refocused when they come back. In this case we want to skip the first focus event, if the
218216
// pane was closed, in order to avoid reopening it unintentionally.
219-
this._canOpenOnNextFocus =
220-
this._document.activeElement !== this._element.nativeElement || this.panelOpen;
217+
this._canOpenOnNextFocus = this.panelOpen || !this._hasFocus();
221218
};
222219

223220
/** `View -> model callback called when value changes` */
@@ -424,7 +421,7 @@ export class MatAutocompleteTrigger
424421
// true. Its main purpose is to handle the case where the input is focused from an
425422
// outside click which propagates up to the `body` listener within the same sequence
426423
// and causes the panel to close immediately (see #3106).
427-
this._document.activeElement !== this._element.nativeElement &&
424+
!this._hasFocus() &&
428425
(!formField || !formField.contains(clickTarget)) &&
429426
(!customOrigin || !customOrigin.contains(clickTarget)) &&
430427
!!this._overlayRef &&
@@ -550,7 +547,7 @@ export class MatAutocompleteTrigger
550547
}
551548
}
552549

553-
if (this._canOpen() && this._document.activeElement === event.target) {
550+
if (this._canOpen() && this._hasFocus()) {
554551
// When the `input` event fires, the input's value will have already changed. This means
555552
// that if we take the `this._element.nativeElement.value` directly, it'll be one keystroke
556553
// behind. This can be a problem when the user selects a value, changes a character while
@@ -579,6 +576,11 @@ export class MatAutocompleteTrigger
579576
}
580577
}
581578

579+
/** Whether the input currently has focus. */
580+
private _hasFocus(): boolean {
581+
return _getFocusedElementPierceShadowDom() === this._element.nativeElement;
582+
}
583+
582584
/**
583585
* In "auto" mode, the label will animate down as soon as focus is lost.
584586
* This causes the value to jump when selecting an option with the mouse.

0 commit comments

Comments
 (0)