Repository navigation
Add an opt-in ariaNotify() transport for screen reader announcements - #5962
Eugene (OEvgeny) wants to merge 11 commits into
Conversation
In 'aria-notify' mode (and 'auto' when the root element supports ariaNotify()), LiveRegionTwin computes the text of each queued entry with a small walker and calls ariaNotify() on the Web Chat root element once per entry; the twin container has no live semantics then. Default stays 'live-region'.
…t repeat entries after switching
|
|
||
| // Detects per instance, on the root element: Web Chat could be rendered in another document, such as an iframe or a popup window. | ||
| // React attaches the ref of the root element after layout effects of its descendants, so only passive effects can read it on mount. | ||
| useEffect(() => { |
There was a problem hiding this comment.
Can this be placed out of the render path? Any reason this check can flip mid-render?
There was a problem hiding this comment.
It can't flip: whether
ariaNotify()exists depends on the browser engine, and it is the same in iframes and popups of that browser. Moved out of state in 6fea16c: a module-level check (Element.prototype.ariaNotifyis a function) runs once on first use and is cached; first use rather than module load, so pages and tests that polyfill or removeariaNotify()before rendering still work. The transport is decided on the first render, with no extra render; eachariaNotify()call still checks its target.accessibility/ariaNotify/6/6 ×3 andaccessibility/liveRegion/34/34 on the pushed head.
| await pageConditions.allImagesLoaded(); | ||
|
|
||
| // THEN: The live region copy has the image as `<img alt>` and the buttons as `<button>` elements. | ||
| expect(pageElements.liveRegion().querySelector('img').getAttribute('alt')).toBe('Bot avatar'); |
There was a problem hiding this comment.
Not sure but it seems the pageElements.liveRegion() should be emptied as we switched to ariaNotify().
There was a problem hiding this comment.
Right: in 'aria-notify' mode the copy only serves to compute the text, but it stayed for internalLiveRegionFadeAfter (60 s here). 6dd07ab removes it right after ariaNotify(); the test now asserts the empty live region and the exact ariaNotify() calls.
There was a problem hiding this comment.
Not sure about the visual screen reader is correct or not after we switch to ariaNotify.
There was a problem hiding this comment.
It was misleading: the box is .webchat__live-region un-hidden by test CSS, showing an aria-hidden copy nobody reads. Since 6dd07ab it is empty in 'aria-notify' mode; what is announced is asserted via the ariaNotify() spy.
| emojiSet: undefined, | ||
|
|
||
| // Live region - Accessibility | ||
| announcementTransport: 'live-region', |
There was a problem hiding this comment.
Maybe call it accessibilityAnnouncementTransport or assistiveTechnologyAnnouncementTransport (AT means screen reader)?
There was a problem hiding this comment.
Renamed to assistiveTechnologyAnnouncementTransport in ed98b5b.
| if (is(picklist(['aria-notify', 'live-region']), announcementTransport)) { | ||
| return announcementTransport; | ||
| } | ||
|
|
||
| typeof announcementTransport === 'undefined' || announcementTransportInvalidValue(); | ||
|
|
||
| return defaultStyleOptions.announcementTransport; |
There was a problem hiding this comment.
If I am right...
| if (is(picklist(['aria-notify', 'live-region']), announcementTransport)) { | |
| return announcementTransport; | |
| } | |
| typeof announcementTransport === 'undefined' || announcementTransportInvalidValue(); | |
| return defaultStyleOptions.announcementTransport; | |
| return parse( | |
| fallback( | |
| optional(picklist(['aria-notify', 'live-region']), 'live-region'), | |
| () => { | |
| announcementTransportInvalidValue(); | |
| return 'live-region'; | |
| } | |
| ), | |
| announcementTransport | |
| ); |
There was a problem hiding this comment.
You're right — applied in 2a9dca4, with a spec for undefined/valid/invalid.
With announcementTransport: 'aria-notify', the copies rendered to compute the announced text stayed in .webchat__live-region (aria-hidden, not live) for internalLiveRegionFadeAfter. Remove them right after they are announced, and assert the empty live region in the ariaNotify tests.
Apply review suggestion: parse with optional() (undefined -> 'live-region', no warning) and fallback() (invalid -> warn, 'live-region'). Add a spec for undefined, valid and invalid values.
Changelog Entry
Added
styleOptions.assistiveTechnologyAnnouncementTransportto announce viaariaNotify()instead of the live region, in PR #5962, by @OEvgenyDescription
Web Chat announces only via its live region, silent when the host hides it. With the experimental option set to
'aria-notify'(default'live-region'), it callsariaNotify()on its root instead, once per entry, falling back to the live region if unsupported.Design
dom-accessibility-apicomputes names, not live region text.webchat:announceevent, thenariaNotify()by default after an NVDA/JAWS pass.Specific Changes
StyleOptions.ts,normalizeStyleOptions.ts(+ spec): option, JSDoc, warns if invalidLiveRegionTwin: cached support check, fallback, one call per new entry, empty live regiongetAnnouncementText.ts: text walkerariaNotify/*.html: calls on the root, empty live region, host hiding it, alt text, buttons, inputs, no repeats after switching, fallback.changelog/<PR#>-<slug>.mdReview Checklist
z-index)package.jsonandpackage-lock.jsonreviewed