Skip to content

Commit 57b066a

Browse files
crisbetojelbourn
authored andcommitted
fix(datepicker): set role on datepicker popup and aria-haspopup on the datepicker toggle (#12008)
Currently the datepicker in touch UI mode has `role="dialog"` which is inherited from `MatDialog`, however it doesn't have a role in popup mode. These changes add the proper role for the popup element, in addition to `aria-haspopup` which was missing from the datepicker toggle button.
1 parent 49119ed commit 57b066a

File tree

4 files changed

+29
-5
lines changed

4 files changed

+29
-5
lines changed

src/lib/datepicker/datepicker-toggle.html

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
1-
<button mat-icon-button type="button" [attr.aria-label]="_intl.openCalendarLabel"
2-
[disabled]="disabled" (click)="_open($event)">
1+
<button
2+
mat-icon-button
3+
type="button"
4+
aria-haspopup="true"
5+
[attr.aria-label]="_intl.openCalendarLabel"
6+
[disabled]="disabled"
7+
(click)="_open($event)">
38

49
<svg
510
*ngIf="!_customIcon"

src/lib/datepicker/datepicker.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ set to something like `new Date(2017, MM, dd)` when the calendar was opened (the
6565
irrelevant in this case).
6666

6767
Notice that the emitted value does not affect the current value in the connected `<input>`, which
68-
is only bound to the selection made in the `month` view. So if the end user closes the calendar
68+
is only bound to the selection made in the `month` view. So if the end user closes the calendar
6969
after choosing a year in `multi-view` mode (by pressing the `ESC` key, for example), the selected
7070
year, emitted by `yearSelected` output, will not cause any change in the value of the date in the
7171
associated `<input>`.
@@ -330,8 +330,9 @@ export class MyApp {}
330330

331331
### Accessibility
332332

333-
The `MatDatepickerInput` directive adds `aria-haspopup` attribute to the native input element, and it
334-
triggers a calendar dialog with `role="dialog"`.
333+
The `MatDatepickerInput` and `MatDatepickerToggle` directives add the `aria-haspopup` attribute to
334+
the native input and toggle button elements respectively, and they trigger a calendar dialog with
335+
`role="dialog"`.
335336

336337
`MatDatepickerIntl` includes strings that are used for `aria-label`s. The datepicker input
337338
should have a placeholder or be given a meaningful label via `aria-label`, `aria-labelledby` or

src/lib/datepicker/datepicker.spec.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,16 @@ describe('MatDatepicker', () => {
185185
expect(testComponent.datepicker.opened).toBe(false, 'Expected datepicker to be closed.');
186186
}));
187187

188+
it('should set the proper role on the popup', fakeAsync(() => {
189+
testComponent.datepicker.open();
190+
fixture.detectChanges();
191+
flush();
192+
193+
const popup = document.querySelector('.cdk-overlay-pane')!;
194+
expect(popup).toBeTruthy();
195+
expect(popup.getAttribute('role')).toBe('dialog');
196+
}));
197+
188198
it('close should close dialog', fakeAsync(() => {
189199
testComponent.touch = true;
190200
fixture.detectChanges();
@@ -800,6 +810,13 @@ describe('MatDatepicker', () => {
800810
flush();
801811
}));
802812

813+
it('should set `aria-haspopup` on the toggle button', () => {
814+
const button = fixture.debugElement.query(By.css('button'));
815+
816+
expect(button).toBeTruthy();
817+
expect(button.nativeElement.getAttribute('aria-haspopup')).toBe('true');
818+
});
819+
803820
it('should open calendar when toggle clicked', () => {
804821
expect(document.querySelector('mat-dialog-container')).toBeNull();
805822

src/lib/datepicker/datepicker.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,7 @@ export class MatDatepicker<D> implements OnDestroy, CanColor {
426426
});
427427

428428
this._popupRef = this._overlay.create(overlayConfig);
429+
this._popupRef.overlayElement.setAttribute('role', 'dialog');
429430

430431
merge(
431432
this._popupRef.backdropClick(),

0 commit comments

Comments
 (0)