Skip to content

Conversation

@johannes-weber
Copy link
Member

@johannes-weber johannes-weber commented Oct 30, 2025

Description

In some cases, when two live regions are used and updated nearly at the same time, one of the announcements sometimes get missed by screen readers (tested with VO on Mac).

With this change, multiple LiveRegion instances are automatically coordinated to prevent

  • screen readers from dropping announcements when they occur simultaneously.
  • Announcements are staggered with a minimum gap to ensure all are heard.

Related links, issue #, if available: AWSUI-61345

How has this been tested?

  • created a test page to manually test the changes
  • add unit tests for this scenario
Review checklist

The following items are to be evaluated by the author(s) and the reviewer(s).

Correctness

  • Changes include appropriate documentation updates.
  • Changes are backward-compatible if not indicated, see CONTRIBUTING.md.
  • Changes do not include unsupported browser features, see CONTRIBUTING.md.
  • Changes were manually tested for accessibility, see accessibility guidelines.

Security

Testing

  • Changes are covered with new/existing unit tests?
  • Changes are covered with new/existing integration tests?

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

@codecov
Copy link

codecov bot commented Oct 30, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 97.24%. Comparing base (a9c90bb) to head (e16a83c).

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #3987   +/-   ##
=======================================
  Coverage   97.24%   97.24%           
=======================================
  Files         858      858           
  Lines       25346    25358   +12     
  Branches     9014     9016    +2     
=======================================
+ Hits        24647    24659   +12     
  Misses        652      652           
  Partials       47       47           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@johannes-weber johannes-weber changed the title fix(live-region): ensure rapid successive announcements are not lost fix: Ensure rapid successive live announcements are not lost Nov 4, 2025
* Screen readers throttle announcements to avoid overwhelming users.
* A 500ms gap ensures each announcement is detected and spoken.
*/
private static readonly MIN_ANNOUNCEMENT_GAP_MS = 500;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

500 seems quite long, maybe you can get away with 250?

if (this._timeoutId === undefined) {
this._timeoutId = setTimeout(() => this._updateElement(false), this.delay * 1000);
// Clear any existing timeout to ensure the latest announcement is used.
if (this._timeoutId !== undefined) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This significantly changes the behavior of the live region. Previously, we throttled announcements — if the live region triggered 50 times in 2 seconds, it would only trigger an update twice (the first one, and another one at the end of the 2s period).

After this update, updates are debounced, not throttled (since each call clears the timeout) and (if I can visualize how this works correctly) if this gets called multiple times, each call will just add to the _nextAvailableSlot. So if trigger the live region 50 times in 2 seconds, you'll only hear one announcement 25 seconds later.

The weird paradox here is that we do want to deduplicate and remove announcements if they happen too frequently (which is why this controller exists), but we don't want to do it between different live regions. Maybe you can preserve the existing behavior, give each live region a unique incrementing ID, and only do the slot behavior if the last slot didn't belong to the current live region. Or, do this check inside _updateElement so that existing behavior doesn't need to be messed with unless there's the edge case that another live region fired and we have to delay our update a little bit more?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants