Skip to content

Commit 0e300d1

Browse files
committed
fix(material/datepicker): prevent calendar from stealing away focus (#31128)
An earlier change added some logic to the calendar to re-focus the active date if an input requiring a full re-render changes which can potentially cause focus to be lost. The problem with this is that if the calendar is used on its own, it might steal away focus even though the user wasn't interacting with it. These changes add a check that focus is inside the calendar before attempting to recapture it. Fixes #30635. (cherry picked from commit 5397b38)
1 parent e63f033 commit 0e300d1

File tree

1 file changed

+9
-3
lines changed

1 file changed

+9
-3
lines changed

src/material/datepicker/calendar.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
ChangeDetectionStrategy,
1414
ChangeDetectorRef,
1515
Component,
16+
ElementRef,
1617
EventEmitter,
1718
Input,
1819
OnChanges,
@@ -41,6 +42,7 @@ import {MAT_SINGLE_DATE_SELECTION_MODEL_PROVIDER, DateRange} from './date-select
4142
import {MatIconButton, MatButton} from '../button';
4243
import {_IdGenerator, CdkMonitorFocus} from '@angular/cdk/a11y';
4344
import {_CdkPrivateStyleLoader, _VisuallyHiddenLoader} from '@angular/cdk/private';
45+
import {_getFocusedElementPierceShadowDom} from '@angular/cdk/platform';
4446

4547
/**
4648
* Possible views for the calendar.
@@ -241,6 +243,7 @@ export class MatCalendar<D> implements AfterContentInit, AfterViewChecked, OnDes
241243
private _dateAdapter = inject<DateAdapter<D>>(DateAdapter, {optional: true})!;
242244
private _dateFormats = inject<MatDateFormats>(MAT_DATE_FORMATS, {optional: true});
243245
private _changeDetectorRef = inject(ChangeDetectorRef);
246+
private _elementRef = inject<ElementRef<HTMLElement>>(ElementRef);
244247

245248
/** An input indicating the type of the header component, if set. */
246249
@Input() headerComponent: ComponentType<any>;
@@ -457,9 +460,12 @@ export class MatCalendar<D> implements AfterContentInit, AfterViewChecked, OnDes
457460
const view = this._getCurrentViewComponent();
458461

459462
if (view) {
460-
// Schedule focus to be moved to the active date since re-rendering
461-
// can blur the active cell. See #29265.
462-
this._moveFocusOnNextTick = true;
463+
// Schedule focus to be moved to the active date since re-rendering can blur the active
464+
// cell (see #29265), however don't do so if focus is outside of the calendar, because it
465+
// can steal away the user's attention (see #30635).
466+
if (this._elementRef.nativeElement.contains(_getFocusedElementPierceShadowDom())) {
467+
this._moveFocusOnNextTick = true;
468+
}
463469

464470
// We need to `detectChanges` manually here, because the `minDate`, `maxDate` etc. are
465471
// passed down to the view via data bindings which won't be up-to-date when we call `_init`.

0 commit comments

Comments
 (0)