Skip to content

Commit 6d726f4

Browse files
authored
feat(material/datepicker): allow for focus restoration to be disabled (#21444)
Adds the ability to disable focus restoration in the datepicker, similar to what we have in the dialog. Fixes #20750.
1 parent f12f6c3 commit 6d726f4

File tree

2 files changed

+42
-2
lines changed

2 files changed

+42
-2
lines changed

src/material/datepicker/datepicker-base.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,18 @@ export abstract class MatDatepickerBase<C extends MatDatepickerControl<D>, S,
348348
@Input()
349349
yPosition: DatepickerDropdownPositionY = 'below';
350350

351+
/**
352+
* Whether to restore focus to the previously-focused element when the calendar is closed.
353+
* Note that automatic focus restoration is an accessibility feature and it is recommended that
354+
* you provide your own equivalent, if you decide to turn it off.
355+
*/
356+
@Input()
357+
get restoreFocus(): boolean { return this._restoreFocus; }
358+
set restoreFocus(value: boolean) {
359+
this._restoreFocus = coerceBooleanProperty(value);
360+
}
361+
private _restoreFocus = true;
362+
351363
/**
352364
* Emits selected year in multiyear view.
353365
* This doesn't imply a change on the selected date.
@@ -572,7 +584,7 @@ export abstract class MatDatepickerBase<C extends MatDatepickerControl<D>, S,
572584
}
573585
};
574586

575-
if (this._focusedElementBeforeOpen &&
587+
if (this._restoreFocus && this._focusedElementBeforeOpen &&
576588
typeof this._focusedElementBeforeOpen.focus === 'function') {
577589
// Because IE moves focus asynchronously, we can't count on it being restored before we've
578590
// marked the datepicker as closed. If the event fires out of sequence and the element that
@@ -744,4 +756,5 @@ export abstract class MatDatepickerBase<C extends MatDatepickerControl<D>, S,
744756
static ngAcceptInputType_disabled: BooleanInput;
745757
static ngAcceptInputType_opened: BooleanInput;
746758
static ngAcceptInputType_touchUi: BooleanInput;
759+
static ngAcceptInputType_restoreFocus: BooleanInput;
747760
}

src/material/datepicker/datepicker.spec.ts

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1119,6 +1119,32 @@ describe('MatDatepicker', () => {
11191119
expect(document.activeElement).toBe(toggle, 'Expected focus to be restored to toggle.');
11201120
});
11211121

1122+
it('should allow for focus restoration to be disabled', () => {
1123+
let toggle = fixture.debugElement.query(By.css('button'))!.nativeElement;
1124+
1125+
fixture.componentInstance.touchUI = false;
1126+
fixture.componentInstance.restoreFocus = false;
1127+
fixture.detectChanges();
1128+
1129+
toggle.focus();
1130+
expect(document.activeElement).toBe(toggle, 'Expected toggle to be focused.');
1131+
1132+
fixture.componentInstance.datepicker.open();
1133+
fixture.detectChanges();
1134+
1135+
let pane = document.querySelector('.cdk-overlay-pane')!;
1136+
1137+
expect(pane).toBeTruthy('Expected calendar to be open.');
1138+
expect(pane.contains(document.activeElement))
1139+
.toBe(true, 'Expected focus to be inside the calendar.');
1140+
1141+
fixture.componentInstance.datepicker.close();
1142+
fixture.detectChanges();
1143+
1144+
expect(document.activeElement)
1145+
.not.toBe(toggle, 'Expected focus not to be restored to toggle.');
1146+
});
1147+
11221148
it('should not override focus if it was moved inside the closed event in touchUI mode',
11231149
fakeAsync(() => {
11241150
const focusTarget = document.createElement('button');
@@ -2318,13 +2344,14 @@ class DatepickerWithFormControl {
23182344
template: `
23192345
<input [matDatepicker]="d">
23202346
<mat-datepicker-toggle [for]="d" [aria-label]="ariaLabel"></mat-datepicker-toggle>
2321-
<mat-datepicker #d [touchUi]="touchUI"></mat-datepicker>
2347+
<mat-datepicker #d [touchUi]="touchUI" [restoreFocus]="restoreFocus"></mat-datepicker>
23222348
`,
23232349
})
23242350
class DatepickerWithToggle {
23252351
@ViewChild('d') datepicker: MatDatepicker<Date>;
23262352
@ViewChild(MatDatepickerInput) input: MatDatepickerInput<Date>;
23272353
touchUI = true;
2354+
restoreFocus = true;
23282355
ariaLabel: string;
23292356
}
23302357

0 commit comments

Comments
 (0)