Skip to content

Commit fda8c7d

Browse files
authored
refactor: allow setting popover role directly (#9869)
1 parent bbe4720 commit fda8c7d

File tree

2 files changed

+50
-9
lines changed

2 files changed

+50
-9
lines changed

packages/popover/src/vaadin-popover.js

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -314,14 +314,22 @@ class Popover extends PopoverPositionMixin(
314314
observer: '__openedChanged',
315315
},
316316

317+
/**
318+
* The `role` attribute value to be set on the popover.
319+
* When not specified, defaults to 'dialog'.
320+
*/
321+
role: {
322+
type: String,
323+
reflectToAttribute: true,
324+
},
325+
317326
/**
318327
* The `role` attribute value to be set on the overlay.
319328
*
320329
* @attr {string} overlay-role
321330
*/
322331
overlayRole: {
323332
type: String,
324-
value: 'dialog',
325333
},
326334

327335
/**
@@ -413,7 +421,7 @@ class Popover extends PopoverPositionMixin(
413421
}
414422

415423
static get observers() {
416-
return ['__sizeChanged(width, height, _overlayElement)', '__updateAriaAttributes(opened, overlayRole, target)'];
424+
return ['__sizeChanged(width, height, _overlayElement)', '__updateAriaAttributes(opened, role, target)'];
417425
}
418426

419427
/**
@@ -520,15 +528,24 @@ class Popover extends PopoverPositionMixin(
520528
super.ready();
521529

522530
this._overlayElement = this.$.overlay;
531+
532+
if (!this.hasAttribute('role')) {
533+
this.role = 'dialog';
534+
}
523535
}
524536

525537
/** @protected */
526-
updated(props) {
527-
super.updated(props);
538+
willUpdate(props) {
539+
super.willUpdate(props);
528540

529541
if (props.has('overlayRole')) {
530-
this.setAttribute('role', this.overlayRole);
542+
this.role = this.overlayRole;
531543
}
544+
}
545+
546+
/** @protected */
547+
updated(props) {
548+
super.updated(props);
532549

533550
if (props.has('accessibleName')) {
534551
if (this.accessibleName) {
@@ -610,7 +627,7 @@ class Popover extends PopoverPositionMixin(
610627
}
611628

612629
/** @private */
613-
__updateAriaAttributes(opened, overlayRole, target) {
630+
__updateAriaAttributes(opened, role, target) {
614631
if (this.__oldTarget) {
615632
const oldEffectiveTarget = this.__oldTarget.ariaTarget || this.__oldTarget;
616633
oldEffectiveTarget.removeAttribute('aria-haspopup');
@@ -621,7 +638,7 @@ class Popover extends PopoverPositionMixin(
621638
if (target) {
622639
const effectiveTarget = target.ariaTarget || target;
623640

624-
const isDialog = overlayRole === 'dialog' || overlayRole === 'alertdialog';
641+
const isDialog = role === 'dialog' || role === 'alertdialog';
625642
effectiveTarget.setAttribute('aria-haspopup', isDialog ? 'dialog' : 'true');
626643

627644
effectiveTarget.setAttribute('aria-expanded', opened ? 'true' : 'false');

packages/popover/test/a11y.test.js

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,23 @@ describe('a11y', () => {
6767
});
6868

6969
describe('ARIA attributes', () => {
70-
it('should set role attribute on the host element to dialog', () => {
70+
it('should set role attribute to dialog', () => {
7171
expect(popover.getAttribute('role')).to.equal('dialog');
7272
});
7373

74-
it('should change role attribute on the host element based on overlayRole', async () => {
74+
it('should allow setting role declaratively', () => {
75+
popover = fixtureSync('<vaadin-popover role="menu"></vaadin-popover>');
76+
expect(popover.role).to.equal('menu');
77+
expect(popover.getAttribute('role')).to.equal('menu');
78+
});
79+
80+
it('should change role attribute when setting role', async () => {
81+
popover.role = 'alertdialog';
82+
await nextUpdate(popover);
83+
expect(popover.getAttribute('role')).to.equal('alertdialog');
84+
});
85+
86+
it('should change role attribute based on overlayRole', async () => {
7587
popover.overlayRole = 'alertdialog';
7688
await nextUpdate(popover);
7789
expect(popover.getAttribute('role')).to.equal('alertdialog');
@@ -97,12 +109,24 @@ describe('a11y', () => {
97109
expect(element.getAttribute('aria-haspopup')).to.equal('dialog');
98110
});
99111

112+
it(`should keep aria-haspopup attribute on the ${prop} when role is set to alertdialog`, async () => {
113+
popover.role = 'alertdialog';
114+
await nextUpdate(popover);
115+
expect(element.getAttribute('aria-haspopup')).to.equal('dialog');
116+
});
117+
100118
it(`should keep aria-haspopup attribute on the ${prop} when overlayRole is set to alertdialog`, async () => {
101119
popover.overlayRole = 'alertdialog';
102120
await nextUpdate(popover);
103121
expect(element.getAttribute('aria-haspopup')).to.equal('dialog');
104122
});
105123

124+
it(`should update aria-haspopup attribute on the ${prop} when role is set to different value`, async () => {
125+
popover.role = 'menu';
126+
await nextUpdate(popover);
127+
expect(element.getAttribute('aria-haspopup')).to.equal('true');
128+
});
129+
106130
it(`should update aria-haspopup attribute on the ${prop} when overlayRole is set to different value`, async () => {
107131
popover.overlayRole = 'menu';
108132
await nextUpdate(popover);

0 commit comments

Comments
 (0)