diff --git a/core/src/components/toast/test/a11y/index.html b/core/src/components/toast/test/a11y/index.html index b2eb88a7ae1..3b9c9adb2df 100644 --- a/core/src/components/toast/test/a11y/index.html +++ b/core/src/components/toast/test/a11y/index.html @@ -34,6 +34,14 @@

Toast - a11y

Present Controller Toast + Present Aria Label Toast + + Update Inner Content @@ -41,6 +49,17 @@

Toast - a11y

const inlineToast = document.querySelector('#inline-toast'); inlineToast.buttons = ['Ok']; + const ariaLabelToast = document.querySelector('#aria-label-toast'); + ariaLabelToast.buttons = [ + { + icon: 'close', + htmlAttributes: { + 'aria-label': 'close button', + 'aria-labelledby': 'close-label', + }, + }, + ]; + const presentToast = async (opts) => { const toast = await toastController.create(opts); diff --git a/core/src/components/toast/test/a11y/toast.e2e.ts b/core/src/components/toast/test/a11y/toast.e2e.ts index 65b24a85b31..f0e1bac41f8 100644 --- a/core/src/components/toast/test/a11y/toast.e2e.ts +++ b/core/src/components/toast/test/a11y/toast.e2e.ts @@ -11,10 +11,10 @@ configs({ directions: ['ltr'] }).forEach(({ title, config }) => { await page.goto(`/src/components/toast/test/a11y`, config); }); test('should not have any axe violations with inline toasts', async ({ page }) => { - const ionToastDidPresent = await page.spyOnEvent('ionToastDidPresent'); + const didPresent = await page.spyOnEvent('ionToastDidPresent'); await page.click('#inline-toast-trigger'); - await ionToastDidPresent.next(); + await didPresent.next(); /** * IonToast overlays the entire screen, so @@ -25,10 +25,10 @@ configs({ directions: ['ltr'] }).forEach(({ title, config }) => { expect(results.violations).toEqual([]); }); test('should not have any axe violations with controller toasts', async ({ page }) => { - const ionToastDidPresent = await page.spyOnEvent('ionToastDidPresent'); + const didPresent = await page.spyOnEvent('ionToastDidPresent'); await page.click('#controller-toast-trigger'); - await ionToastDidPresent.next(); + await didPresent.next(); /** * IonToast overlays the entire screen, so @@ -38,5 +38,19 @@ configs({ directions: ['ltr'] }).forEach(({ title, config }) => { const results = await new AxeBuilder({ page }).disableRules('color-contrast').analyze(); expect(results.violations).toEqual([]); }); + + test('should have aria-labelledby and aria-label added to the button when htmlAttributes is set', async ({ + page, + }) => { + const didPresent = await page.spyOnEvent('ionToastDidPresent'); + + await page.click('#aria-label-toast-trigger'); + await didPresent.next(); + + const toastButton = page.locator('#aria-label-toast .toast-button'); + + await expect(toastButton).toHaveAttribute('aria-labelledby', 'close-label'); + await expect(toastButton).toHaveAttribute('aria-label', 'close button'); + }); }); }); diff --git a/core/src/components/toast/toast-interface.ts b/core/src/components/toast/toast-interface.ts index 02108e06476..c2b3aca5d7f 100644 --- a/core/src/components/toast/toast-interface.ts +++ b/core/src/components/toast/toast-interface.ts @@ -31,6 +31,7 @@ export interface ToastButton { side?: 'start' | 'end'; role?: 'cancel' | string; cssClass?: string | string[]; + htmlAttributes?: { [key: string]: any }; handler?: () => boolean | void | Promise; } diff --git a/core/src/components/toast/toast.tsx b/core/src/components/toast/toast.tsx index 4f397d94a7c..0b783bc83e0 100644 --- a/core/src/components/toast/toast.tsx +++ b/core/src/components/toast/toast.tsx @@ -405,7 +405,14 @@ export class Toast implements ComponentInterface, OverlayInterface { return (
{buttons.map((b) => ( -