From 790cfdb503a9847c3aabf61b8efe56b0b8e5ecad Mon Sep 17 00:00:00 2001 From: Marissa Huysentruyt Date: Fri, 17 Oct 2025 16:41:46 -0400 Subject: [PATCH 1/6] feat(tray): add dismissHelper function --- packages/tray/src/Tray.ts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/packages/tray/src/Tray.ts b/packages/tray/src/Tray.ts index 901910c9380..d2a73407b1d 100644 --- a/packages/tray/src/Tray.ts +++ b/packages/tray/src/Tray.ts @@ -81,6 +81,23 @@ export class Tray extends SpectrumElement { } } + /** + * Returns a visually hidden dismiss button for mobile screen reader accessibility. + * This button is placed before and after tray content to allow mobile screen reader + * users (particularly VoiceOver on iOS) to easily dismiss the overlay. + */ + protected get dismissHelper(): TemplateResult { + return html` +
+ +
+ `; + } + private dispatchClosed(): void { this.dispatchEvent( new Event('close', { @@ -131,7 +148,9 @@ export class Tray extends SpectrumElement { tabindex="-1" @transitionend=${this.handleTrayTransitionend} > + ${this.dismissHelper} + ${this.dismissHelper} `; } From 209eeddf1dfd4aa825fe4a3eda696159847af6aa Mon Sep 17 00:00:00 2001 From: Marissa Huysentruyt Date: Fri, 17 Oct 2025 16:42:36 -0400 Subject: [PATCH 2/6] refactor(tray): expand visually-hidden selector for dismiss buttons --- packages/tray/src/tray.css | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/tray/src/tray.css b/packages/tray/src/tray.css index d6bd646b275..33ec07f30b4 100644 --- a/packages/tray/src/tray.css +++ b/packages/tray/src/tray.css @@ -30,6 +30,7 @@ sp-underlay { overscroll-behavior: contain; } +.visually-hidden, ::slotted(.visually-hidden) { border: 0; clip: rect(0, 0, 0, 0); From 7fecbc760341f75e514aaaa073e45fffb53b68bc Mon Sep 17 00:00:00 2001 From: Marissa Huysentruyt Date: Fri, 17 Oct 2025 16:43:58 -0400 Subject: [PATCH 3/6] docs(tray): add tray docs with visually hidden dismiss --- packages/tray/README.md | 49 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 3 deletions(-) diff --git a/packages/tray/README.md b/packages/tray/README.md index 3bbdaadb38d..85bca444c92 100644 --- a/packages/tray/README.md +++ b/packages/tray/README.md @@ -7,19 +7,19 @@ [![See it on NPM!](https://img.shields.io/npm/v/@spectrum-web-components/tray?style=for-the-badge)](https://www.npmjs.com/package/@spectrum-web-components/tray) [![How big is this package in your project?](https://img.shields.io/bundlephobia/minzip/@spectrum-web-components/tray?style=for-the-badge)](https://bundlephobia.com/result?p=@spectrum-web-components/tray) -``` +```bash yarn add @spectrum-web-components/tray ``` Import the side effectful registration of `` via: -``` +```js import '@spectrum-web-components/tray/sp-tray.js'; ``` When looking to leverage the `Tray` base class as a type and/or for extension purposes, do so via: -``` +```js import { Tray } from '@spectrum-web-components/tray'; ``` @@ -70,3 +70,46 @@ A tray has a single default `slot`. ### Accessibility `` presents a page blocking experience and should be opened with the `Overlay` API using the `modal` interaction to ensure that the content appropriately manages the presence of other content in the tab order of the page and the availability of that content for a screen reader. + +#### Mobile screen reader support + +The `` component automatically includes visually hidden dismiss buttons before and after its content to support mobile screen readers. This is particularly important for VoiceOver on iOS, where users navigate through interactive elements sequentially. + +These built-in dismiss buttons: + +- Are visually hidden but accessible to screen readers +- Use `tabindex="-1"` to prevent keyboard tab navigation interference +- Allow mobile screen reader users to easily dismiss the tray from either the beginning or end of the content +- Are labeled "Dismiss" for clear screen reader announcements + +This dismiss helper pattern is also implemented in the [``](https://opensource.adobe.com/spectrum-web-components/components/picker/) component, which uses the same approach when rendering menu content in a tray on mobile devices. + +Simply place your content inside the tray - the dismiss buttons are automatically rendered: + +```html + + + Toggle menu content + + + + Deselect + Select Inverse + Feather... + Select and Mask... + + + + + + + Toggle dialog content + + + +

New messages

+ You have 5 new messages. +
+
+
+``` From be0a5e699130071dabf3cc7b3b706259b695c8a5 Mon Sep 17 00:00:00 2001 From: Marissa Huysentruyt Date: Tue, 21 Oct 2025 14:33:33 -0400 Subject: [PATCH 4/6] feat(dialog-base): add dismissHelper for visually-hidden buttons --- packages/dialog/src/DialogBase.ts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/packages/dialog/src/DialogBase.ts b/packages/dialog/src/DialogBase.ts index 2973c20ac69..7d35e8a584d 100644 --- a/packages/dialog/src/DialogBase.ts +++ b/packages/dialog/src/DialogBase.ts @@ -194,6 +194,23 @@ export class DialogBase extends FocusVisiblePolyfillMixin(SpectrumElement) { super.update(changes); } + /** + * Returns a visually hidden dismiss button for mobile screen reader accessibility. + * This button is placed before and after dialog content to allow mobile screen reader + * users (particularly VoiceOver on iOS) to easily dismiss the overlay. + */ + protected get dismissHelper(): TemplateResult { + return html` +
+ +
+ `; + } + protected renderDialog(): TemplateResult { return html` From 26d42d2dd7c155c4a21277021654e8550a1c7fed Mon Sep 17 00:00:00 2001 From: Marissa Huysentruyt Date: Tue, 21 Oct 2025 14:36:32 -0400 Subject: [PATCH 5/6] feat(dialog-wrapper): implement conditional dismissHelper buttons --- packages/dialog/src/DialogWrapper.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/dialog/src/DialogWrapper.ts b/packages/dialog/src/DialogWrapper.ts index f6d6953fe9b..d46df91f638 100644 --- a/packages/dialog/src/DialogWrapper.ts +++ b/packages/dialog/src/DialogWrapper.ts @@ -125,6 +125,7 @@ export class DialogWrapper extends DialogBase { } return html` + ${this.dismissHelper} + ${!this.dismissable ? this.dismissHelper : nothing} `; } } From 225faf7ee80660b5854c2b48e1822eaa7268b644 Mon Sep 17 00:00:00 2001 From: Marissa Huysentruyt Date: Tue, 21 Oct 2025 14:46:02 -0400 Subject: [PATCH 6/6] feat(modal): add visually-hidden styles for dialog dismissHelpers --- packages/modal/src/modal.css | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/packages/modal/src/modal.css b/packages/modal/src/modal.css index 996d22d3d6d..5c632d34982 100644 --- a/packages/modal/src/modal.css +++ b/packages/modal/src/modal.css @@ -24,3 +24,16 @@ .modal { overflow: visible; } + +.visually-hidden { + border: 0; + clip: rect(0, 0, 0, 0); + clip-path: inset(50%); + height: 1px; + margin: 0 -1px -1px 0; + overflow: hidden; + padding: 0; + position: absolute; + width: 1px; + white-space: nowrap; +}