Repository navigation
feat(toast): standalone api/a11y - #6817
rise-erpelding wants to merge 5 commits into
Conversation
|
📚 Branch Preview Links🔍 Gen1 Visual Regression Test ResultsWhen a visual regression test fails (or has previously failed while working on this branch), its results can be found in the following URLs:
Deployed to Azure Blob Storage: If the changes are expected, update the |
69c0541 to
4660a38
Compare
b89a2be to
da68439
Compare
| this.setAttribute('role', 'alertdialog'); | ||
| this.setAttribute('aria-modal', 'false'); | ||
| this.setAttribute('tabindex', '0'); |
There was a problem hiding this comment.
Intended to work with the container, which isn't implemented yet.
cdransf
left a comment
There was a problem hiding this comment.
Looks great! Just a few questions. ✨
5t3ph
left a comment
There was a problem hiding this comment.
Looking good so far! Just a few minor things.
|
|
||
| Q1, Q2, Q3, Q7, Q12, and Q15 were previously listed here; all six are now resolved, see the [Decision log](#decision-log). | ||
|
|
||
| ### Architecture and behavior |
There was a problem hiding this comment.
Maybe add a question to track needing to resolve the double-announcement of the icon label?
I experienced the same, nothing jumps out at me as to why 🤔
There was a problem hiding this comment.
Ok, I didn't do this, but I'd love your opinion on whether I still should? It now only announces the icon if icon-label is set.
I tested this with NVDA, Voiceover + Safari, and Voiceover + Chrome/Edge. So now, the only double-announcement that happens is with Voiceover + Chrome/Edge, and that's only if icon-label is set.
| - Bare message text produces an `aria-label` derived from that text. | ||
| - A single light-DOM message element with an `id` is referenced by `aria-labelledby`. |
There was a problem hiding this comment.
I'm a little confused why we are showing/supporting both of these given this info will ultimately be passed in a JS API (not as live DOM content), right? Or is that still unsettled?
There was a problem hiding this comment.
I think originally we discussed aria-labelledby, and somehow that turned into 🤷♀️ why not both? But it's true that supporting both will complicate things unnecessarily.
It feels like once we build out the queue and we're storing message content, bare message text has the advantage. I'm not well-versed in accessibility enough to know if there's an advantage to aria-labelledby vs. aria-label but I keep coming back to the idea of aria-label being simpler (and aligned with 1st-gen, although that isn't necessarily a consideration). Thoughts on either direction?
There was a problem hiding this comment.
Per our previous conversation, we'll reevaluate when container is being built, but we should be able to use aria-labelledby. I left the current logic as-is.
|
Does Toast need two slot controllers mentioned here in shared resources ? |
Screen.Recording.2026-10-02.at.3.49.19.PM.movWorks super well here with screen reader and labelling. After you tab to close button from the alert the screen reader doesn't read out the close button unless you escape the toast and return with |
|
This has been updated to address feedback and is ready for re-review! If there's something I missed addressing (either by pushing up a change or commenting on it), please bring it to my attention! I did some screen reader testing (Voiceover with Chrome, Edge, Safari, NVDA on AssistivLabs), it does appear to be announcing correctly; the double-icon announcement is less apparent now than it was as we're only announcing the icon if @aramos-adobe The close button did announce in my screen reader tests when tabbing into the toast, but I also see that it does not using the Screen Reader feature in Storybook. I think this may be a quirk of that particular Screen Reader feature rather than a bug, but let me know if you think otherwise! |
Description
This PR implements the gen2 standalone Toast API and accessibility skeleton for the toast migration. It establishes the individual toast contract that the future toast container will compose.
This is intentionally not a shippable standalone toast and is currently mostly unstyled. The migration plan requires the future container to own queueing, placement, stacking, timing, and focus behavior. The live-region announcement strategy is also still provisional and should be treated as an explicit review item.
Included
openstatevariantwith the gen2 valuesneutral,info,positive, andnegative(no variant styling)iconLabelfor semantic or decorative variant iconsactionLabelfor the constrained first-party action buttonclose()methodswc-closedismissal eventswc-open,swc-after-open, andswc-after-closelifecycle eventsswc-toast-actioneventicon-label=""for decorative iconsReview notes
alertdialog/aria-modal/focusable-host model is provisional. Review whether it remains appropriate once the container's focus and notification model is implemented. Do not treat the current standalone skeleton as the final accessibility contract.opendoes not emit an opening lifecycle sequence.Motivation and context
Toast is being migrated to gen2 as two related pieces: an individual notification element and a future container/queue. This PR establishes the individual element's public API and rendering contract so the container work has a stable surface to build on.
The implementation keeps shared API and lifecycle behavior in the core base class while leaving Lit rendering, Spectrum child components, icons, and styles in the SWC subclass.
Related issue(s)
Screenshots (if appropriate)
The component has placeholder presentation until the styling phase. Storybook provides dark preview backgrounds so the current toast structure and controls remain visible.
Author's checklist
Reviewer's checklist
patch,minor, ormajorfeaturesManual review test cases
Inspect the API and default toast
openis reflected, the default message is present, and the defaultneutralvariant is used.variantcontrol throughneutral,info,positive, andnegative; expect the corresponding icon treatment to render.Verify action and dismissal behavior
swc-toasthost itself in the Anatomy canvas, not the nested button. Then runwindow.__toast = $0; window.__toast.addEventListener('swc-toast-action', (event) => console.log(event.type, event.target));in the Console.Undoaction. Expect aswc-toast-actionlog from the toast host, and expect the toast to remain open. The event is not wired to a Storybook action logger in this story.window.__toast.open = true;to reopen it, then runwindow.__cancelClose = (event) => event.preventDefault(); window.__toast.addEventListener('swc-close', window.__cancelClose);.swc-closeto be dispatched but the toast to remain open because the listener canceled it.Verify lifecycle behavior
swc-openandswc-closeto occur at the start of the state change andswc-after-open/swc-after-closeafter the rendered transition settles.(Optional) Review the future container boundary
Device review
Accessibility testing checklist
Required: Complete the applicable manual checks below and record the browser, operating system, and assistive technology used. The live-region behavior is explicitly provisional for this phase.
Keyboard
Tabto move through the toast and verify that the focus order reaches the action button and close button in a logical order, with visible focus indicators when the placeholder styling permits.swc-toast-actionwithout automatic dismissal. Enter activation of the action is not an acceptance criterion for this phase.Screen reader
actionLabeltoUndo, then click Toggle toast to open the toast.alertdialognamed “File saved”, and that theUndoand Close controls have useful accessible names.icon-labelvalues. Verify that the variant icon has its expected accessible label, uses the custom label when provided, and is omitted from the accessibility tree whenicon-label="". Record whether the icon label is announced once or more than once; VoiceOver and NVDA may differ.