Skip to content

Commit 594457e

Browse files
committed
refactor: use aria-modal in date-picker instead of aria-hidden
1 parent 858c565 commit 594457e

File tree

4 files changed

+37
-54
lines changed

4 files changed

+37
-54
lines changed

packages/date-picker/src/vaadin-date-picker-mixin.js

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
* Copyright (c) 2016 - 2025 Vaadin Ltd.
44
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
55
*/
6-
import { hideOthers } from '@vaadin/a11y-base/src/aria-hidden.js';
76
import { DelegateFocusMixin } from '@vaadin/a11y-base/src/delegate-focus-mixin.js';
87
import { isKeyboardActive } from '@vaadin/a11y-base/src/focus-utils.js';
98
import { KeyboardMixin } from '@vaadin/a11y-base/src/keyboard-mixin.js';
@@ -461,6 +460,20 @@ export const DatePickerMixin = (subclass) =>
461460
// Currently only supported for locales that start the week on Monday.
462461
this.toggleAttribute('week-numbers', this.showWeekNumbers && this.__effectiveI18n.firstDayOfWeek === 1);
463462
}
463+
464+
if (props.has('opened') || props.has('_noInput')) {
465+
const content = this._overlayContent;
466+
if (this.opened) {
467+
content.setAttribute('role', 'dialog');
468+
// Mark as modal on mobile if the input can not be accessed
469+
if (this._noInput) {
470+
content.setAttribute('aria-modal', 'true');
471+
}
472+
} else if (props.get('opened')) {
473+
content.removeAttribute('role');
474+
content.removeAttribute('aria-modal');
475+
}
476+
}
464477
}
465478

466479
/** @protected */
@@ -910,9 +923,6 @@ export const DatePickerMixin = (subclass) =>
910923
input.blur();
911924
this._overlayContent.focusDateElement();
912925
}
913-
914-
const focusables = this._noInput ? content : [input, content];
915-
this.__showOthers = hideOthers(focusables);
916926
}
917927

918928
/** @private */
@@ -959,11 +969,6 @@ export const DatePickerMixin = (subclass) =>
959969

960970
/** @protected */
961971
_onOverlayClosed() {
962-
// Reset `aria-hidden` state.
963-
if (this.__showOthers) {
964-
this.__showOthers();
965-
this.__showOthers = null;
966-
}
967972
window.removeEventListener('scroll', this._boundOnScroll, true);
968973

969974
if (this._closedByEscape) {

packages/date-picker/src/vaadin-date-picker-overlay-content-mixin.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,9 @@ export const DatePickerOverlayContentMixin = (superClass) =>
165165
}
166166

167167
/** @protected */
168-
_initControllers() {
168+
firstUpdated() {
169+
super.firstUpdated();
170+
169171
this.addController(
170172
new MediaQueryController(this._desktopMediaQuery, (matches) => {
171173
this._desktopMode = matches;

packages/date-picker/src/vaadin-date-picker-overlay-content.js

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -53,15 +53,6 @@ class DatePickerOverlayContent extends DatePickerOverlayContentMixin(
5353
</div>
5454
`;
5555
}
56-
57-
/** @protected */
58-
firstUpdated() {
59-
super.firstUpdated();
60-
61-
this.setAttribute('role', 'dialog');
62-
63-
this._initControllers();
64-
}
6556
}
6657

6758
defineCustomElement(DatePickerOverlayContent);

packages/date-picker/test/wai-aria.test.js

Lines changed: 20 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,26 @@ describe('WAI-ARIA', () => {
2929
expect(calendar.getAttribute('aria-hidden')).to.equal(focusable ? null : 'true');
3030
});
3131
});
32+
33+
it('should toggle role attribute on the overlay content on open', async () => {
34+
await open(datePicker);
35+
const content = datePicker._overlayContent;
36+
expect(content.getAttribute('role')).to.equal('dialog');
37+
38+
datePicker.close();
39+
expect(content.hasAttribute('role')).to.be.false;
40+
});
41+
42+
it('should toggle aria-modal attribute on the overlay content on open if fullscreen', async () => {
43+
datePicker._fullscreen = true;
44+
45+
await open(datePicker);
46+
const content = datePicker._overlayContent;
47+
expect(content.getAttribute('aria-modal')).to.equal('true');
48+
49+
datePicker.close();
50+
expect(content.hasAttribute('aria-modal')).to.be.false;
51+
});
3252
});
3353

3454
describe('overlay contents', () => {
@@ -84,39 +104,4 @@ describe('WAI-ARIA', () => {
84104
expect(todayElement.getAttribute('aria-label')).to.match(/, Today$/u);
85105
});
86106
});
87-
88-
describe('aria-hidden', () => {
89-
let wrapper, datePicker, input, button;
90-
91-
beforeEach(async () => {
92-
wrapper = fixtureSync(`
93-
<div>
94-
<button>Button</button>
95-
<vaadin-date-picker></vaadin-date-picker>
96-
<input placeholder="input" />
97-
</div>
98-
`);
99-
await nextRender();
100-
[button, datePicker, input] = wrapper.children;
101-
});
102-
103-
it('should set aria-hidden on other elements when overlay is opened', async () => {
104-
await open(datePicker);
105-
expect(button.getAttribute('aria-hidden')).to.equal('true');
106-
expect(input.getAttribute('aria-hidden')).to.equal('true');
107-
});
108-
109-
it('should not set aria-hidden on slotted input and overlay element', async () => {
110-
await open(datePicker);
111-
expect(datePicker.inputElement.hasAttribute('aria-hidden')).to.be.false;
112-
expect(datePicker.$.overlay.hasAttribute('aria-hidden')).to.be.false;
113-
});
114-
115-
it('should remove aria-hidden from other elements when overlay is closed', async () => {
116-
await open(datePicker);
117-
datePicker.close();
118-
expect(button.hasAttribute('aria-hidden')).to.be.false;
119-
expect(input.hasAttribute('aria-hidden')).to.be.false;
120-
});
121-
});
122107
});

0 commit comments

Comments
 (0)