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 (