fix(modal): buttons are highlighted with VoiceOver (#26180)

resolves #26156
This commit is contained in:
Liam DeBeasi
2022-10-31 14:02:09 -05:00
committed by GitHub
parent bbbd37bc49
commit 1504b8888d
2 changed files with 17 additions and 7 deletions

View File

@ -348,7 +348,7 @@ export class Modal implements ComponentInterface, OverlayInterface {
componentWillLoad() { componentWillLoad() {
const { breakpoints, initialBreakpoint, swipeToClose, el } = this; const { breakpoints, initialBreakpoint, swipeToClose, el } = this;
this.inheritedAttributes = inheritAttributes(el, ['role']); this.inheritedAttributes = inheritAttributes(el, ['aria-label', 'role']);
/** /**
* If user has custom ID set then we should * If user has custom ID set then we should
@ -879,11 +879,8 @@ export class Modal implements ComponentInterface, OverlayInterface {
return ( return (
<Host <Host
no-router no-router
aria-modal="true"
role="dialog"
tabindex="-1" tabindex="-1"
{...(htmlAttributes as any)} {...(htmlAttributes as any)}
{...inheritedAttributes}
style={{ style={{
zIndex: `${20000 + this.overlayIndex}`, zIndex: `${20000 + this.overlayIndex}`,
}} }}
@ -911,7 +908,20 @@ export class Modal implements ComponentInterface, OverlayInterface {
{mode === 'ios' && <div class="modal-shadow"></div>} {mode === 'ios' && <div class="modal-shadow"></div>}
<div class="modal-wrapper ion-overlay-wrapper" part="content" ref={(el) => (this.wrapperEl = el)}> <div
/*
role and aria-modal must be used on the
same element. They must also be set inside the
shadow DOM otherwise ion-button will not be highlighted
when using VoiceOver: https://bugs.webkit.org/show_bug.cgi?id=247134
*/
role="dialog"
{...inheritedAttributes}
aria-modal="true"
class="modal-wrapper ion-overlay-wrapper"
part="content"
ref={(el) => (this.wrapperEl = el)}
>
{showHandle && ( {showHandle && (
<button <button
class="modal-handle" class="modal-handle"

View File

@ -13,7 +13,7 @@ test.describe('modal: a11y', () => {
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent'); const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
const button = page.locator('#open-modal'); const button = page.locator('#open-modal');
const modal = page.locator('ion-modal'); const modal = page.locator('ion-modal .modal-wrapper');
await expect(modal).toHaveAttribute('role', 'dialog'); await expect(modal).toHaveAttribute('role', 'dialog');
@ -32,7 +32,7 @@ test.describe('modal: a11y', () => {
await page.setContent(` await page.setContent(`
<ion-modal role="alertdialog"></ion-modal> <ion-modal role="alertdialog"></ion-modal>
`); `);
const modal = page.locator('ion-modal'); const modal = page.locator('ion-modal .modal-wrapper');
await expect(modal).toHaveAttribute('role', 'alertdialog'); await expect(modal).toHaveAttribute('role', 'alertdialog');
}); });