From 37c6428f052f9fa72c1b055f460a5153093f4084 Mon Sep 17 00:00:00 2001 From: Brandy Carney Date: Thu, 27 Jul 2023 13:00:57 -0400 Subject: [PATCH 1/4] docs(api): add accessibility section for new htmlAttributes property --- docs/api/action-sheet.md | 8 ++++++- docs/api/alert.md | 11 ++++++++-- docs/api/toast.md | 47 +++++++++++++++++++++------------------- 3 files changed, 41 insertions(+), 25 deletions(-) diff --git a/docs/api/action-sheet.md b/docs/api/action-sheet.md index a11e669c194..30daf740b93 100644 --- a/docs/api/action-sheet.md +++ b/docs/api/action-sheet.md @@ -94,10 +94,14 @@ import CssCustomProperties from '@site/static/usage/v7/action-sheet/theming/css- ## Accessibility +### Screen Readers + Action Sheets are given a `role` of [`dialog`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/dialog_role). In order to align with the ARIA spec, either the `aria-label` or `aria-labelledby` attribute must be set. It is strongly recommended that every Action Sheet have the `header` property defined, as Ionic will automatically set `aria-labelledby` to point to the header element. However, if you choose not to include a `header`, an alternative is to use the `htmlAttributes` property to provide a descriptive `aria-label` or set a custom `aria-labelledby` value. +Buttons containing text will be read by a screen reader. If a button contains only an icon, a label should be assigned to the button by passing `aria-label` or `aria-labelledby` to the `htmlAttributes` property. The `aria-label` property accepts a text description and `aria-labelledby` accepts an element that contains the description of the button. + ## Interfaces ### ActionSheetButton @@ -108,6 +112,8 @@ interface ActionSheetButton { role?: 'cancel' | 'destructive' | 'selected' | string; icon?: string; cssClass?: string | string[]; + id?: string; + htmlAttributes?: { [key: string]: any }; handler?: () => boolean | void | Promise; data?: T; } @@ -150,4 +156,4 @@ interface ActionSheetOptions { ## Slots - \ No newline at end of file + diff --git a/docs/api/alert.md b/docs/api/alert.md index f6e5d5ee581..430bedfc1ee 100644 --- a/docs/api/alert.md +++ b/docs/api/alert.md @@ -111,6 +111,8 @@ import Customization from '@site/static/usage/v7/alert/customization/index.md'; ## Accessibility +### Screen Readers + Ionic automatically sets the Alert's `role` to either [`alertdialog`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/alertdialog_role) if there are any inputs or buttons included, or [`alert`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/alert_role) if there are none. If the `header` property is defined for the Alert, the `aria-labelledby` attribute will be automatically set to the header's ID. The `subHeader` element will be used as a fallback if `header` is not defined. Similarly, the `aria-describedby` attribute will be automatically set to the ID of the `message` element if that property is defined. @@ -119,17 +121,22 @@ It is strongly recommended that your Alert have a `message`, as well as either a All ARIA attributes can be manually overwritten by defining custom values in the `htmlAttributes` property of the Alert. +Buttons containing text will be read by a screen reader. If a description other than the existing text is desired, a label can be assigned to the button by passing `aria-label` or `aria-labelledby` to the `htmlAttributes` property. The `aria-label` property accepts a text description and `aria-labelledby` accepts an element that contains the description of the button. ## Interfaces ### AlertButton ```typescript +type AlertButtonOverlayHandler = boolean | void | { [key: string]: any }; + interface AlertButton { text: string; role?: 'cancel' | 'destructive' | string; cssClass?: string | string[]; - handler?: (value: any) => boolean | void | {[key: string]: any}; + id?: string; + htmlAttributes?: { [key: string]: any }; + handler?: (value: any) => AlertButtonOverlayHandler | Promise; } ``` @@ -199,4 +206,4 @@ interface AlertOptions { ## Slots - \ No newline at end of file + diff --git a/docs/api/toast.md b/docs/api/toast.md index 10a785c2086..c69cd3d011b 100644 --- a/docs/api/toast.md +++ b/docs/api/toast.md @@ -86,6 +86,30 @@ import ThemingPlayground from '@site/static/usage/v7/toast/theming/index.md'; +## Accessibility + +### Focus Management + +Toasts are intended to be subtle notifications and are not intended to interrupt the user. User interaction should not be required to dismiss the toast. As a result, focus is not automatically moved to a toast when one is presented. + +### Screen Readers + +`ion-toast` has `role="status"` and `aria-live="polite"` set on the inner `.toast-content` element. This causes screen readers to only announce the toast message and header. Buttons and icons will not be announced. + +`aria-live` causes screen readers to announce the content of the toast when it is updated. However, since the attribute is set to `'polite'`, screen readers should not interrupt the current task. + +Since toasts are intended to be subtle notification, `aria-live` should never be set to `"assertive"`. If developers need to interrupt the user with an important message, we recommend using an [alert](./alert). + +Buttons containing text will be read by a screen reader. If a button contains only an icon, a label should be assigned to the button by passing `aria-label` or `aria-labelledby` to the `htmlAttributes` property. The `aria-label` property accepts a text description and `aria-labelledby` accepts an element that contains the description of the button. + +### Tips + +While this is not a complete list, here are some guidelines to follow when using toasts. + +* Do not require user interaction to dismiss toasts. For example, having a "Dismiss" button in the toast is fine, but the toast should also automatically dismiss on its own after a timeout period. If you need user interaction for a notification, consider using an [alert](./alert) instead. + +* For toasts with long messages, consider adjusting the `duration` property to allow users enough time to read the content of the toast. + ## Interfaces ### ToastButton @@ -97,6 +121,7 @@ interface ToastButton { side?: 'start' | 'end'; role?: 'cancel' | string; cssClass?: string | string[]; + htmlAttributes?: { [key: string]: any }; handler?: () => boolean | void | Promise; } ``` @@ -126,28 +151,6 @@ interface ToastOptions { } ``` -## Accessibility - -### Focus Management - -Toasts are intended to be subtle notifications and are not intended to interrupt the user. User interaction should not be required to dismiss the toast. As a result, focus is not automatically moved to a toast when one is presented. - -### Screen Readers - -`ion-toast` has `role="status"` and `aria-live="polite"` set on the inner `.toast-content` element. This causes screen readers to only announce the toast message and header. Buttons and icons will not be announced. - -`aria-live` causes screen readers to announce the content of the toast when it is updated. However, since the attribute is set to `'polite'`, screen readers should not interrupt the current task. - -Since toasts are intended to be subtle notification, `aria-live` should never be set to `"assertive"`. If developers need to interrupt the user with an important message, we recommend using an [alert](./alert). - -### Tips - -While this is not a complete list, here are some guidelines to follow when using toasts. - -* Do not require user interaction to dismiss toasts. For example, having a "Dismiss" button in the toast is fine, but the toast should also automatically dismiss on its own after a timeout period. If you need user interaction for a notification, consider using an [alert](./alert) instead. - -* For toasts with long messages, consider adjusting the `duration` property to allow users enough time to read the content of the toast. - ## Properties From eb800ec570dd39a0327a5e26d78cd096b6f98325 Mon Sep 17 00:00:00 2001 From: Brandy Carney Date: Mon, 31 Jul 2023 16:17:42 -0400 Subject: [PATCH 2/4] docs(accessibility): update sections for overlays to be more descriptive --- docs/api/action-sheet.md | 32 +++++++++++++++++++++++++++++++- docs/api/alert.md | 33 ++++++++++++++++++++++++++++++++- docs/api/toast.md | 22 +++++++++++++++++++++- 3 files changed, 84 insertions(+), 3 deletions(-) diff --git a/docs/api/action-sheet.md b/docs/api/action-sheet.md index 30daf740b93..5955dbfc949 100644 --- a/docs/api/action-sheet.md +++ b/docs/api/action-sheet.md @@ -96,11 +96,41 @@ import CssCustomProperties from '@site/static/usage/v7/action-sheet/theming/css- ### Screen Readers +Action Sheets set aria properties in order to be [accessible](../reference/glossary#a11y) to screen readers, but these properties can be overridden if they aren't descriptive enough or don't align with how the action sheet is being used in an app. + +#### Role + Action Sheets are given a `role` of [`dialog`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/dialog_role). In order to align with the ARIA spec, either the `aria-label` or `aria-labelledby` attribute must be set. +#### Action Sheet Description + It is strongly recommended that every Action Sheet have the `header` property defined, as Ionic will automatically set `aria-labelledby` to point to the header element. However, if you choose not to include a `header`, an alternative is to use the `htmlAttributes` property to provide a descriptive `aria-label` or set a custom `aria-labelledby` value. -Buttons containing text will be read by a screen reader. If a button contains only an icon, a label should be assigned to the button by passing `aria-label` or `aria-labelledby` to the `htmlAttributes` property. The `aria-label` property accepts a text description and `aria-labelledby` accepts an element that contains the description of the button. +```javascript +actionSheetController.create({ + htmlAttributes: { + 'aria-label': 'action sheet dialog', + }, +}); +``` + +#### Action Sheet Buttons Description + +Buttons containing text will be read by a screen reader. If a button contains only an icon, or a description other than the existing text is desired, a label should be assigned to the button by passing `aria-label` to the `htmlAttributes` property on the button. + +```javascript +actionSheetController.create({ + header: 'Header', + buttons: [ + { + icon: 'close', + htmlAttributes: { + 'aria-label': 'close', + }, + }, + ], +}); +``` ## Interfaces diff --git a/docs/api/alert.md b/docs/api/alert.md index 430bedfc1ee..dc10c6643fd 100644 --- a/docs/api/alert.md +++ b/docs/api/alert.md @@ -113,15 +113,46 @@ import Customization from '@site/static/usage/v7/alert/customization/index.md'; ### Screen Readers +Alerts set aria properties in order to be [accessible](../reference/glossary#a11y) to screen readers, but these properties can be overridden if they aren't descriptive enough or don't align with how the alert is being used in an app. + +#### Role + Ionic automatically sets the Alert's `role` to either [`alertdialog`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/alertdialog_role) if there are any inputs or buttons included, or [`alert`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/alert_role) if there are none. +#### Alert Description + If the `header` property is defined for the Alert, the `aria-labelledby` attribute will be automatically set to the header's ID. The `subHeader` element will be used as a fallback if `header` is not defined. Similarly, the `aria-describedby` attribute will be automatically set to the ID of the `message` element if that property is defined. It is strongly recommended that your Alert have a `message`, as well as either a `header` or `subHeader`, in order to align with the ARIA spec. If you choose not to include a `header` or `subHeader`, an alternative is to provide a descriptive `aria-label` using the `htmlAttributes` property. +```javascript +alertController.create({ + message: 'This is an alert with custom aria attributes.', + htmlAttributes: { + 'aria-label': 'alert dialog', + }, +}); +``` + All ARIA attributes can be manually overwritten by defining custom values in the `htmlAttributes` property of the Alert. -Buttons containing text will be read by a screen reader. If a description other than the existing text is desired, a label can be assigned to the button by passing `aria-label` or `aria-labelledby` to the `htmlAttributes` property. The `aria-label` property accepts a text description and `aria-labelledby` accepts an element that contains the description of the button. +#### Alert Buttons Description + +Buttons containing text will be read by a screen reader. If a description other than the existing text is desired, a label can be set on the button by passing `aria-label` to the `htmlAttributes` property on the button. + +```javascript +alertController.create({ + header: 'Header', + buttons: [ + { + text: 'Exit', + htmlAttributes: { + 'aria-label': 'close', + }, + }, + ], +}); +``` ## Interfaces diff --git a/docs/api/toast.md b/docs/api/toast.md index c69cd3d011b..93fbd98ce74 100644 --- a/docs/api/toast.md +++ b/docs/api/toast.md @@ -94,13 +94,33 @@ Toasts are intended to be subtle notifications and are not intended to interrupt ### Screen Readers +Toasts set aria properties in order to be [accessible](../reference/glossary#a11y) to screen readers, but these properties can be overridden if they aren't descriptive enough or don't align with how the toast is being used in an app. + +#### Role + `ion-toast` has `role="status"` and `aria-live="polite"` set on the inner `.toast-content` element. This causes screen readers to only announce the toast message and header. Buttons and icons will not be announced. `aria-live` causes screen readers to announce the content of the toast when it is updated. However, since the attribute is set to `'polite'`, screen readers should not interrupt the current task. Since toasts are intended to be subtle notification, `aria-live` should never be set to `"assertive"`. If developers need to interrupt the user with an important message, we recommend using an [alert](./alert). -Buttons containing text will be read by a screen reader. If a button contains only an icon, a label should be assigned to the button by passing `aria-label` or `aria-labelledby` to the `htmlAttributes` property. The `aria-label` property accepts a text description and `aria-labelledby` accepts an element that contains the description of the button. +#### Toast Buttons Description + +Buttons containing text will be read by a screen reader. If a button contains only an icon, or a description other than the existing text is desired, a label should be assigned to the button by passing `aria-label` to the `htmlAttributes` property on the button. + +```javascript +toastController.create({ + header: 'Header', + buttons: [ + { + icon: 'close', + htmlAttributes: { + 'aria-label': 'close', + }, + }, + ], +}); +``` ### Tips From f164d9c6526b1195bca706d863f5808a4c0009a9 Mon Sep 17 00:00:00 2001 From: Brandy Carney Date: Mon, 31 Jul 2023 16:58:11 -0400 Subject: [PATCH 3/4] docs(accessibility): add tabs for the frameworks for the code samples --- docs/api/action-sheet.md | 113 +++++++++++++++++++++++++++++++++++++- docs/api/alert.md | 114 ++++++++++++++++++++++++++++++++++++++- docs/api/toast.md | 64 +++++++++++++++++++++- 3 files changed, 286 insertions(+), 5 deletions(-) diff --git a/docs/api/action-sheet.md b/docs/api/action-sheet.md index 5955dbfc949..8d6844e3d3e 100644 --- a/docs/api/action-sheet.md +++ b/docs/api/action-sheet.md @@ -1,6 +1,9 @@ --- title: "ion-action-sheet" --- +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + import Props from '@ionic-internal/component-api/v7/action-sheet/props.md'; import Events from '@ionic-internal/component-api/v7/action-sheet/events.md'; import Methods from '@ionic-internal/component-api/v7/action-sheet/methods.md'; @@ -106,20 +109,68 @@ Action Sheets are given a `role` of [`dialog`](https://developer.mozilla.org/en- It is strongly recommended that every Action Sheet have the `header` property defined, as Ionic will automatically set `aria-labelledby` to point to the header element. However, if you choose not to include a `header`, an alternative is to use the `htmlAttributes` property to provide a descriptive `aria-label` or set a custom `aria-labelledby` value. + + + + +```javascript +const actionSheet = await this.actionSheetController.create({ + htmlAttributes: { + 'aria-label': 'action sheet dialog', + }, +}); +``` + + + + + +```javascript +const actionSheet = await this.actionSheetController.create({ + htmlAttributes: { + 'aria-label': 'action sheet dialog', + }, +}); +``` + + + + + ```javascript -actionSheetController.create({ +useIonActionSheet({ htmlAttributes: { 'aria-label': 'action sheet dialog', }, }); ``` + + + + +```javascript +const actionSheet = await actionSheetController.create({ + htmlAttributes: { + 'aria-label': 'action sheet dialog', + }, +}); +``` + + + + + #### Action Sheet Buttons Description Buttons containing text will be read by a screen reader. If a button contains only an icon, or a description other than the existing text is desired, a label should be assigned to the button by passing `aria-label` to the `htmlAttributes` property on the button. + + + + ```javascript -actionSheetController.create({ +const actionSheet = await this.actionSheetController.create({ header: 'Header', buttons: [ { @@ -132,6 +183,64 @@ actionSheetController.create({ }); ``` + + + + +```javascript +const actionSheet = await this.actionSheetController.create({ + header: 'Header', + buttons: [ + { + icon: 'close', + htmlAttributes: { + 'aria-label': 'close', + }, + }, + ], +}); +``` + + + + + +```javascript +useIonActionSheet({ + header: 'Header', + buttons: [ + { + icon: 'close', + htmlAttributes: { + 'aria-label': 'close', + }, + }, + ], +}); +``` + + + + + +```javascript +const actionSheet = await actionSheetController.create({ + header: 'Header', + buttons: [ + { + icon: 'close', + htmlAttributes: { + 'aria-label': 'close', + }, + }, + ], +}); +``` + + + + + ## Interfaces ### ActionSheetButton diff --git a/docs/api/alert.md b/docs/api/alert.md index dc10c6643fd..e645cf2f397 100644 --- a/docs/api/alert.md +++ b/docs/api/alert.md @@ -125,8 +125,51 @@ If the `header` property is defined for the Alert, the `aria-labelledby` attribu It is strongly recommended that your Alert have a `message`, as well as either a `header` or `subHeader`, in order to align with the ARIA spec. If you choose not to include a `header` or `subHeader`, an alternative is to provide a descriptive `aria-label` using the `htmlAttributes` property. + + + + +```javascript +const alert = await this.alertController.create({ + message: 'This is an alert with custom aria attributes.', + htmlAttributes: { + 'aria-label': 'alert dialog', + }, +}); +``` + + + + + +```javascript +const alert = await this.alertController.create({ + message: 'This is an alert with custom aria attributes.', + htmlAttributes: { + 'aria-label': 'alert dialog', + }, +}); +``` + + + + + +```javascript +useIonAlert({ + message: 'This is an alert with custom aria attributes.', + htmlAttributes: { + 'aria-label': 'alert dialog', + }, +}); +``` + + + + + ```javascript -alertController.create({ +const alert = await alertController.create({ message: 'This is an alert with custom aria attributes.', htmlAttributes: { 'aria-label': 'alert dialog', @@ -134,14 +177,59 @@ alertController.create({ }); ``` + + + + + All ARIA attributes can be manually overwritten by defining custom values in the `htmlAttributes` property of the Alert. #### Alert Buttons Description Buttons containing text will be read by a screen reader. If a description other than the existing text is desired, a label can be set on the button by passing `aria-label` to the `htmlAttributes` property on the button. + + + + +```javascript +const alert = await this.alertController.create({ + header: 'Header', + buttons: [ + { + text: 'Exit', + htmlAttributes: { + 'aria-label': 'close', + }, + }, + ], +}); +``` + + + + + +```javascript +const alert = await this.alertController.create({ + header: 'Header', + buttons: [ + { + text: 'Exit', + htmlAttributes: { + 'aria-label': 'close', + }, + }, + ], +}); +``` + + + + + ```javascript -alertController.create({ +useIonAlert({ header: 'Header', buttons: [ { @@ -154,6 +242,28 @@ alertController.create({ }); ``` + + + + +```javascript +const alert = await alertController.create({ + header: 'Header', + buttons: [ + { + text: 'Exit', + htmlAttributes: { + 'aria-label': 'close', + }, + }, + ], +}); +``` + + + + + ## Interfaces ### AlertButton diff --git a/docs/api/toast.md b/docs/api/toast.md index 93fbd98ce74..982e0723b9d 100644 --- a/docs/api/toast.md +++ b/docs/api/toast.md @@ -108,8 +108,12 @@ Since toasts are intended to be subtle notification, `aria-live` should never be Buttons containing text will be read by a screen reader. If a button contains only an icon, or a description other than the existing text is desired, a label should be assigned to the button by passing `aria-label` to the `htmlAttributes` property on the button. + + + + ```javascript -toastController.create({ +const toast = await this.toastController.create({ header: 'Header', buttons: [ { @@ -122,6 +126,64 @@ toastController.create({ }); ``` + + + + +```javascript +const toast = await this.toastController.create({ + header: 'Header', + buttons: [ + { + icon: 'close', + htmlAttributes: { + 'aria-label': 'close', + }, + }, + ], +}); +``` + + + + + +```javascript +useIonToast({ + header: 'Header', + buttons: [ + { + icon: 'close', + htmlAttributes: { + 'aria-label': 'close', + }, + }, + ], +}); +``` + + + + + +```javascript +const toast = await toastController.create({ + header: 'Header', + buttons: [ + { + icon: 'close', + htmlAttributes: { + 'aria-label': 'close', + }, + }, + ], +}); +``` + + + + + ### Tips While this is not a complete list, here are some guidelines to follow when using toasts. From 4229be3de4f1bb6719f8779024c31ec42754cd4f Mon Sep 17 00:00:00 2001 From: Brandy Carney Date: Fri, 4 Aug 2023 12:42:22 -0400 Subject: [PATCH 4/4] docs(toast): improve description for when button text is announced --- docs/api/toast.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/api/toast.md b/docs/api/toast.md index 982e0723b9d..ea4cf7a7126 100644 --- a/docs/api/toast.md +++ b/docs/api/toast.md @@ -98,7 +98,7 @@ Toasts set aria properties in order to be [accessible](../reference/glossary#a11 #### Role -`ion-toast` has `role="status"` and `aria-live="polite"` set on the inner `.toast-content` element. This causes screen readers to only announce the toast message and header. Buttons and icons will not be announced. +`ion-toast` has `role="status"` and `aria-live="polite"` set on the inner `.toast-content` element. This causes screen readers to only announce the toast message and header. Buttons and icons will not be announced when the toast is presented. `aria-live` causes screen readers to announce the content of the toast when it is updated. However, since the attribute is set to `'polite'`, screen readers should not interrupt the current task. @@ -106,7 +106,7 @@ Since toasts are intended to be subtle notification, `aria-live` should never be #### Toast Buttons Description -Buttons containing text will be read by a screen reader. If a button contains only an icon, or a description other than the existing text is desired, a label should be assigned to the button by passing `aria-label` to the `htmlAttributes` property on the button. +Buttons containing text will be read by a screen reader when they are interacted with. If a button contains only an icon, or a description other than the existing text is desired, a label should be assigned to the button by passing `aria-label` to the `htmlAttributes` property on the button.